# Shai-Hulud strikes again: CHAINDROP worm hits 400+ npm packages

Compromised keyv maintainer account pushed CHAINDROP worm via preinstall hooks, backdooring 400+ npm packages and harvesting developer credentials.

- Payout: Real-world hack
- Severity: critical
- Program: npm keyv
- Credited: Elastic Security Labs
- Disclosed: 2026-08-06
- Write-up quality: 8/10
- Original: https://www.elastic.co/security-labs/threat-command/shai-hulud-chaindrop-npm-supply-chain
- Library page: https://bugbountylibrary.com/r/blog%3Aelastic-co-security-labs-threat-command-shai-hulud-chaindrop-npm-supply-chain
- Tags: domain:oss impact:data-leak impact:mass-exploit kind:incident platform:threat-intel sev:critical tech:github-actions tech:nodejs technique:chained technique:source-review vuln:secrets-leak

**Target:** npm packages / developer machines (preinstall hook, setup.mjs dropper)
**Root cause:** Attacker compromised the keyv maintainer's npm account and trojanized the monorepo, adding a preinstall hook that runs setup.mjs to download bun and execute an obfuscated credential-stealing payload.
**Steps:**
1. Compromise keyv maintainer npm credentials
2. Add `preinstall: node setup.mjs` to package.json of every subpackage
3. setup.mjs checks for bun, else downloads bun v1.3.13 from official release page, extracts, runs Math_Symbol.js, deletes temp dir
4. Payload (711KB, Base91 string encoding, control-flow flattened) harvests 300+ credential patterns (AI tooling, AWS/GCP/Azure, GitHub, Vault, SSH, K8s, npm)
5. Exfil: gzip + AES-256-GCM with random key, RSA-encrypt key with attacker pubkey; resolve C2 via Ethereum contract `0xE1f2395ee43e45A1556EC6438a88c31B83493103` with RPC fallbacks, else GitHub signed marker `thebeautifulmarchoftime`, else public GitHub repo
6. Worm: if stolen npm token has write + bypass_2fa, enumerate writable packages, download tarball, inject math_init.js/setup.mjs, patch package.json preinstall, bump patch, republish
7. Also injects `.claude/settings.json` SessionStart hook and `.vscode/tasks.json` folderOpen task into up to 50 branches per repo via GitHub App token
**How found:** Elastic's supply-chain monitoring project flagged a malicious npm package via Slack alert at 5:39 AM EST, prompting triage of the keyv monorepo and detonation of the payload.
**Exploitation:** Victim installs any trojanized package; preinstall hook auto-runs setup.mjs with no interaction, downloads bun, executes obfuscated payload that sweeps local credential stores, encrypts and exfiltrates to attacker-controlled C2 resolved dynamically via smart contract. Stolen npm tokens with bypass_2fa propagate the worm to all co-owned packages.
**Escalation:** Worm self-propagates across maintainer's publish scope; GitHub App token extends to committing hooks into up to 50 branches per repo, infecting developers who merely open the repo in VS Code or Claude Code.
**Insight:** Worm propagation gates on npm tokens with both write permission and bypass_2fa — audit automation tokens for that flag; also check .claude/settings.json SessionStart and .vscode/tasks.json folderOpen hooks, which trigger on repo open without any install.
