ChainDrop: Inside a Self-Propagating npm Worm

ChainDrop: Inside a Self-Propagating npm Worm
ChainDrop is a self-propagating npm worm that infected hundreds of packages, stole developer and cloud credentials, and republished itself through compromised npm tokens while also targeting GitHub Actions and AI coding tool environments. Its operators used Ethereum-based C2 resolution and could silently rotate infrastructure without updating the malware, with evidence linking the campaign to Shai-Hulud-style tooling. #ChainDrop #ShaiHulud #Ethereum #npm #GitHubActions

Keypoints

  • ChainDrop infected over 400 npm packages that are downloaded hundreds of millions of times each week.
  • The worm steals cloud credentials, npm and GitHub tokens, SSH keys, and other sensitive developer data.
  • It can scrape temporary credentials from GitHub Actions runner memory and use stolen npm publishing tokens to republish infected packages.
  • Unit 42 identified 453 public GitHub repositories across five accounts matching the worm’s exfiltration patterns and observed execution in 10 distinct environments.
  • The malware establishes persistence through VS Code and Claude Code configuration files, with latent support for macOS LaunchAgents and Linux systemd services.
  • Its command-and-control infrastructure is resolved through an Ethereum smart contract, allowing silent domain rotation without changing the malware.
  • Some activity was detected by Palo Alto Networks products, including Koi Agentic Endpoint Security and Cortex XDR behavioral detections.

MITRE Techniques

  • [T1059.007 ] JavaScript – ChainDrop executes its payload through Bun and JavaScript dropper files to run the worm and launch credential theft (‘executes Math_Symbol.js or math_init.js via the bun nodejs runtime’).
  • [T1059.006 ] Python – An embedded Python helper is used on GitHub Actions runners to locate Runner.Worker and scrape live process memory (‘an embedded Python helper…locates the Runner.Worker process’).
  • [T1005 ] Data from Local System – The worm harvests files, configs, tokens, histories, and wallet data from infected hosts (‘it sweeps the infected machine to harvest credentials from the environment’).
  • [T1528 ] Steal Application Access Token – It invokes GitHub CLI authentication commands to steal GitHub credentials (‘invokes “gh auth token” to extract the local GitHub CLI authentication token’).
  • [T1555 ] Credentials from Password Stores – The payload gathers stored developer and service credentials such as npm, GitHub, SSH, Vault, and cloud secrets (‘Git credentials…npm and GitHub tokens…SSH keys…Vault tokens’).
  • [T1057 ] Process Discovery – The memory scraper searches for the Runner.Worker process on GitHub Actions runners (‘locates the Runner.Worker process’).
  • [T1003 ] OS Credential Dumping – The worm reads /proc//maps and /proc//mem to extract secrets from process memory (‘opens /proc//maps and /proc//mem’).
  • [T1547.001 ] Registry Run Keys / Startup Folder – The malware creates persistence through developer tooling startup hooks and OS autostart mechanisms (‘it writes a .vscode/tasks.json…SessionStart command hook… macOS LaunchAgent… Linux systemd user service’).
  • [T1127 ] Trusted Developer Utilities Proxy Execution – It uses legitimate tools like Bun and Claude Code/VS Code hooks as execution vehicles (‘using a legitimate runtime as a portable execution vehicle’).
  • [T1105 ] Ingress Tool Transfer – The dropper downloads Bun from GitHub and fetches additional payload material (‘It downloads Bun 1.3.13 from the legitimate Oven GitHub repository’).
  • [T1027 ] Obfuscated Files or Information – The payload is heavily obfuscated with Base91, custom permutation, and AES-256-GCM layers (‘protected by three nested layers of obfuscation and encryption’).
  • [T1106 ] Native API – The worm reads returned HTTP responses, parses JSON, and evaluates code from the server (‘parses it as JSON and evaluates whatever comes back’).
  • [T1090 ] Proxy – It relies on Cloudflare-proxied infrastructure and multiple public RPC endpoints to hide and route C2 traffic (‘both domains are proxied through Cloudflare’s…infrastructure’).
  • [T1568.002 ] Domain Generation Algorithms – The new domain is described as randomized and DGA-like (‘randomized 12-character string on the .icu top-level domain’).
  • [T1567.002 ] Exfiltration to Cloud Storage – The worm uploads stolen data through GitHub repositories and Actions artifacts as alternate exfiltration paths (‘uploads it as an Actions artifact…public repositories’).
  • [T1021.004 ] SSH – The malware steals SSH keys and related access material from developer systems (‘SSH keys’).
  • [T1552.001 ] Credentials in Files – It collects secrets from files such as .env, .netrc, and configuration files (‘ .env files .netrc Application configuration’).
  • [T1552.004 ] Private Keys – The worm explicitly targets SSH keys and other private key material (‘SSH keys’).
  • [T1555.003 ] Credentials from Web Browsers – Not directly mentioned; omitted.
  • [T1027.013 ] Encrypted/Encoded File – The exfiltration and payload components are stored and transmitted in encrypted form (‘JSON-serialized, gzipped, encrypted with a random AES-256-GCM key’).

Indicators of Compromise

  • [File hashes ] malicious payload and setup variants – 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc, 54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668, and 2 more hashes.
  • [Domains ] C2 and exfiltration infrastructure – awqhnjewqjkl[.]icu, npm-cache[.]com, and 2 more domains.
  • [URLs ] C2 endpoint and probe path – hxxps://npm-cache[.]com:443/router, hxxp://awqhnjewqjkl[.]icu/cdn-cgi/rum?
  • [IP addresses ] observed C2 destinations – 104.21.91[.]101, 172.67.215[.]154.
  • [Ethereum addresses ] resolver contract and operator wallet – 0xE1f2395ee43e45A1556EC6438a88c31B83493103, 0x55f9780e1492344b7417fa723aedc4d0b97f31cd.
  • [Transaction hashes ] C2 rotation and contract activity – 0xc55920f1bd0531b6738153068a666c080ddded47e6256f1fd980d51c0b507c91.
  • [GitHub markers ] repository and commit-search indicators – Shai-Hulud: Here We Go Again, thebeautifulmarchoftime, and thebeautifulsnadsoftime.
  • [File names ] dropped persistence and payload files – setup.mjs, math_init.js, Math_Symbol.js, .vscode/tasks.json, .claude/settings.json.
  • [Service and artifact names ] latent persistence artifacts – com.user.gh-token-monitor.plist, gh-token-monitor.service, gh-token-monitor.sh.


Read more: https://unit42.paloaltonetworks.com/chaindrop-npm-worm-analysis/