Shai-Hulud npm Worm: 868 Packages and 2B Monthly Downloads Hijacked
On 4 August 2026 a new Shai-Hulud wave hit npm. After the keyv maintainer account was hijacked, 868 packages totaling more than 2 billion monthly downloads were injected with a self-spreading worm. preinstall hooks, a bundled Bun runtime, and IDE hooks can sweep credentials across organizations in about 30 minutes.
On 4 August 2026 the npm registry was hit by a supply-chain campaign code-named Shai-Hulud (the sandworm). The new wave started from a hijacked GitHub account belonging to the keyv maintainer. Using preinstall lifecycle hooks, a bundled Bun runtime, and IDE auto-trigger files, attackers injected backdoors into dozens of popular packages — including keyv, cacheable, flat-cache, file-entry-cache, cacheable-request, and cache-manager — in about 30 minutes, then self-spread downstream via npm automation tokens. By the evening of 4 August, Aikido, JFrog, and other monitors had confirmed at least 868 npm packages (1,381 versions) poisoned, totaling about 2 billion monthly downloads. Compromised second-tier maintainers already include well-known orgs such as @deliveroo/reevent, @picsart/ai-sdk, @qlik/embed-runtime, @or-sdk/invitations, and picasso.js.
Incident Overview
keyv is one of the most popular key-value abstraction layers in Node, at about 127 million weekly downloads for the package itself, and a transitive dependency of tools such as ESLint. The same maintainer also ships high-traffic cache utilities: cacheable, cacheable-request, flat-cache, file-entry-cache. After taking the GitHub account, attackers used legitimate credentials to push malicious commits to main and immediately published versions that carried GitHub Actions provenance. The poisoned packages therefore shipped with official signatures.
The two primary injected files are setup.mjs and Math_Symbol.js. package.json gained "preinstall": "node setup.mjs". On npm install, setup.mjs acts as a thin loader, silently downloads the Bun 1.3.13 standalone runtime, and uses it to run the 728 KB obfuscated payload Math_Symbol.js, bypassing host Node hooks and common audit tools.
Technical Details
1. Credential harvesting and multi-channel exfil
On infected hosts the worm typically:
- Scans
.npmrcand local caches for npm automation tokens, then live-checks them withregistry.npmjs.org/-/whoami; - Grabs GitHub PATs, OAuth tokens, and OIDC JWTs (including publish ID tokens in Actions runner memory);
- Walks 200+ credential patterns across AWS, GCP, Azure, EC2/ECS metadata, Vault, Kubernetes ServiceAccount tokens, Stripe, Slack, SSH private keys, and crypto wallets;
- Encrypts results and drops them into attacker-created GitHub repos (description uniformly
Shai-Hulud: Here We Go Again) plus hardcoded HTTPS / DNS channels.
2. Self-propagation
With a working npm token, the worm hijacks every package that identity can write: download the original tarball, copy the malicious sample to package/math_init.js, overwrite scripts.preinstall, bump the patch version, and PUT straight to the npm registry. Combined with npm 12+ OIDC trusted publishing, one stolen credential can spread to hundreds of packages in minutes.
3. IDE and AI coding-agent re-trigger
The worm also plants five files on the target GitHub repo's main branch — .vscode/tasks.json, .vscode/setup.mjs, .claude/settings.json, .claude/math_init.js, .claude/setup.mjs — so execution does not depend on npm install:
.vscode/tasks.jsonrunsnode .claude/setup.mjswhen VS Code opens the folder;.claude/settings.jsonrunsnode .vscode/setup.mjsvia a SessionStart hook when Claude Code starts a session.
Even with --ignore-scripts or npm 12, opening a poisoned repo directory as a developer or AI agent still auto-runs the payload.
4. Second-pass GitHub Actions credential theft
If the GitHub token has workflow permission, the worm enumerates repos that identity could push since September, creates a dependabot/github_actions/format/setup-formatter branch on one of them, injects a workflow named Run Copilot, and serializes ${{ toJSON(secrets) }} into artifact format-results.txt for download.
Impact Assessment
This is an ecosystem-scale supply-chain incident. keyv@6.0.0 (~604 million monthly downloads), flat-cache@6.1.24 (580 million), file-entry-cache@11.1.6 (571 million), and cacheable-request@13.0.20 (137 million) cover nearly every Node project. Hijacking one maintainer walks the trust graph across companies. Namespace-whitelist dependency audits miss hijacked legitimate publishes and cannot cut the chain in time.
The main payload SHA-256 is public: 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc. Microsoft Defender tags it Trojan:npm/MalBun.A. Dependency trees are deep enough that most victim teams never notice they pulled a hijacked package. Public PoCs and exfil infra have already landed in multiple major ransomware groups' toolkits within 24 hours.
Remediation
- Pin keyv back to
5.6.0. Check every dependency graph forkeyv@6.0.0,flat-cache@6.1.24,file-entry-cache@11.1.6,cacheable-request@13.0.20,cacheable@2.5.1,@cacheable/memory@2.2.1,cache-manager@7.2.10,@cacheable/node-cache@3.1.2,@cacheable/utils@2.5.1,@cacheable/net@2.1.1,ecto@5.0.1; - Treat any
mainpublish after 09:39 UTC on 4 August as untrusted. Review recent maintainer-initiated versions and compare SHA-256; - Before rotating credentials, remove token-revocation watchers that may sit in
claude/settings.json,.vscode/tasks.json, orsetup.mjs; - Immediately revoke possibly exposed npm automation tokens, GitHub PATs, GitHub Apps, and AWS/GCP/Azure/Vault/Kubernetes/SSH/Stripe/Slack credentials. Wipe CI runners built around 4 August;
- Upgrade to npm 12+ to block unapproved preinstall by default. IDE hook paths still work — disable auto-tasks on untrusted directories in IDEs and AI agents;
- When enabling npm OIDC trusted publishing, add a human approval step so stolen tokens cannot silently publish;
- Add repo monitors for: new/changed preinstall / postinstall / prepare scripts; runtime processes connecting to
github.com/oven-sh/bunor any non-npm registry endpoint; unexpected.claude,.vscode, orsetup.mjsartifacts; and repos whose description isShai-Hulud: Here We Go Again.
References
- JFrog Security Research: Major Shai Hulud campaign strikes npm again, affecting keyv and 400+ packages
- Aikido Security: keyv and friends compromised in active Shai-Hulud supply chain attack
- OX Security: A Massive Shai-Hulud Campaign Hits npm: 440+ Packages Compromised, Over 2B Monthly Downloads
- The Hacker News: Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks
- CyberPress: Shai-Hulud npm Worm Compromises 868 Packages With Over 2 Billion Monthly Installs
- GitHub PoC / IOC: exploit reference implementation and IOC index (related samples)