#!/usr/bin/env python3 """Supply chain malware artifact analysis agent. Analyzes software supply chain compromise indicators including package integrity, build pipeline artifacts, dependency confusion, and trojanized updates. """ import os import sys import json import hashlib import re import subprocess from datetime import datetime try: import requests HAS_REQUESTS = True except ImportError: HAS_REQUESTS = False def compute_hash(filepath): hashes = {} for algo in ("md5", "sha1", "sha256"): h = hashlib.new(algo) with open(filepath, "rb") as f: for chunk in iter(lambda: f.read(65536), b""): h.update(chunk) hashes[algo] = h.hexdigest() return hashes def check_npm_package(package_name): if not HAS_REQUESTS: return {"error": "requests not installed"} url = f"https://registry.npmjs.org/{package_name}" try: resp = requests.get(url, timeout=15) resp.raise_for_status() data = resp.json() latest = data.get("dist-tags", {}).get("latest", "") versions = list(data.get("versions", {}).keys()) maintainers = data.get("maintainers", []) return { "name": package_name, "latest": latest, "version_count": len(versions), "maintainers": [m.get("name") for m in maintainers], } except requests.RequestException as e: return {"error": str(e)} def check_pypi_package(package_name): if not HAS_REQUESTS: return {"error": "requests not installed"} url = f"https://pypi.org/pypi/{package_name}/json" try: resp = requests.get(url, timeout=15) resp.raise_for_status() data = resp.json() info = data.get("info", {}) return { "name": info.get("name"), "version": info.get("version"), "author": info.get("author"), "release_count": len(data.get("releases", {})), } except requests.RequestException as e: return {"error": str(e)} def detect_typosquat_packages(target_name): permutations = set() for i in range(len(target_name)): permutations.add(target_name[:i] + target_name[i+1:]) for i in range(len(target_name) - 1): swapped = list(target_name) swapped[i], swapped[i+1] = swapped[i+1], swapped[i] permutations.add("".join(swapped)) permutations.add(target_name.replace("-", "_")) permutations.add(target_name.replace("_", "-")) permutations.discard(target_name) return sorted(permutations) def analyze_package_scripts(package_json_path): with open(package_json_path, "r") as f: pkg = json.load(f) findings = [] scripts = pkg.get("scripts", {}) for hook in ["preinstall", "postinstall", "preuninstall"]: if hook in scripts: cmd = scripts[hook] findings.append({ "type": "install_hook", "hook": hook, "command": cmd[:200], "severity": "HIGH" if any(s in cmd.lower() for s in ["curl", "wget", "eval", "exec", "base64"]) else "MEDIUM", }) deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})} for dep, ver in deps.items(): if ver.startswith("http") or ver.startswith("git"): findings.append({ "type": "url_dependency", "package": dep, "source": ver[:200], "severity": "HIGH", }) return {"name": pkg.get("name"), "findings": findings} def analyze_python_setup(setup_py_path): with open(setup_py_path, "r") as f: content = f.read() findings = [] patterns = [ (r"os\.system\(", "os.system() execution"), (r"subprocess\.", "subprocess execution"), (r"exec\(", "exec() code execution"), (r"eval\(", "eval() code execution"), (r"base64\.b64decode", "Base64 decoding"), (r"socket\.", "Network socket usage"), ] for pattern, description in patterns: if re.search(pattern, content): findings.append({ "type": "suspicious_setup_code", "pattern": description, "severity": "HIGH", }) return {"file": setup_py_path, "findings": findings} if __name__ == "__main__": print("=" * 60) print("Supply Chain Malware Artifact Analysis Agent") print("Package integrity, typosquat detection, install hook analysis") print("=" * 60) target = sys.argv[1] if len(sys.argv) > 1 else None if not target: print("\n[DEMO] Usage:") print(" python agent.py # Analyze npm package") print(" python agent.py npm: # Check npm registry") print(" python agent.py pypi: # Check PyPI registry") sys.exit(0) if target.startswith("npm:"): pkg_name = target[4:] print(f"\n[*] Checking npm: {pkg_name}") info = check_npm_package(pkg_name) typos = detect_typosquat_packages(pkg_name) print(json.dumps(info, indent=2)) print(f"\n Potential typosquats: {typos[:10]}") elif target.startswith("pypi:"): pkg_name = target[5:] print(f"\n[*] Checking PyPI: {pkg_name}") info = check_pypi_package(pkg_name) print(json.dumps(info, indent=2)) elif os.path.exists(target): basename = os.path.basename(target) if basename == "package.json": result = analyze_package_scripts(target) elif basename == "setup.py": result = analyze_python_setup(target) else: result = {"file": target, "hashes": compute_hash(target)} print(json.dumps(result, indent=2))