Shai-Hulud Resurgence: Self-Propagating npm Worm Compromises Keyv, Cacheable, and Hundreds of Downstream Packages
August 6th, 2026
Critical

Our Cyber Threat Intelligence Unit is monitoring an active npm supply chain compromise that began August 4, 2026, with the malicious publication of [email protected]. The campaign belongs to the Shai-Hulud malware family and is widely referred to as "ChainDrop." An attacker compromised the GitHub account of the maintainer behind keyv and cacheable and pushed malicious commits to the source repositories, which then published through the projects' legitimate GitHub Actions pipeline, giving the poisoned releases valid OIDC and SLSA provenance. The packages carry a preinstall hook that downloads the Bun runtime and runs an obfuscated payload that harvests cloud, CI/CD, npm, GitHub, and AI coding tool credentials. Using stolen npm tokens, the worm autonomously republishes itself into unrelated namespaces; confirmed scope is 444 packages / 2,212 versions (StepSecurity) to 868 packages / 1,381 versions (Aikido), with combined downloads exceeding 2 billion per month. A separate path in .claude/settings.json and .vscode/tasks.json runs the payload when a developer opens an affected repository in VS Code or Claude Code, independent of installation, though both require workspace trust. The C2 channel is bidirectional and can trigger remote code execution, not just credential theft. Any environment with an affected package or open repository in an IDE is compromised. Do not rotate credentials until the worm's token-revocation watcher is disabled, as premature revocation can cause destructive local cleanup.
Technical Details
Threat Type: Software supply chain compromise / self-propagating npm worm / credential harvester with RCE capability.
Severity: Critical.
Affected Packages (11 confirmed releases from the compromised account):
[email protected] (safe: 5.6.0, all 5.x, and 6.0.0-rc.1)
[email protected], [email protected], [email protected], [email protected], [email protected]
@cacheable/[email protected], @cacheable/[email protected], @cacheable/[email protected], @cacheable/[email protected]
Plus several hundred additional packages across unrelated namespaces (@servicetitan, @onereach, @or-sdk, @ornikar, @qlik, @nebula.js, @deliveroo, @picsart, @hubsync), spread via stolen npm tokens.
Total counts vary by vendor and are still climbing. Verify current exposure against a live tracker rather than a fixed list.
Affected Scope: Node.js/npm environments, CI/CD pipelines, and developer workstations using VS Code or Claude Code. keyv, flat-cache, and file-entry-cache sit under ESLint, so indirect exposure is common.
Attack Chain:
Initial Access: Maintainer's GitHub account compromised; malicious commits pushed directly to main.
Pipeline Abuse: Malicious commits published through the real GitHub Actions release workflow, giving the packages valid SLSA provenance. dist/ output stayed byte-identical to the clean release.
Stage 1: setup.mjs preinstall hook downloads Bun v1.3.13 from official GitHub release assets if not already present.
Stage 2: setup.mjs runs the ~728 KB obfuscated Math_Symbol.js/math_init.js bundle via Bun (basE91-encoded strings; modules tagged [collector], [dispatcher], [provenance], [publish]).
Credential Harvesting: Cloud (AWS/GCP/Azure), Vault, Kubernetes, GitHub, npm, SSH, and AI tool credentials (Claude, Codex, Cursor, OpenAI, Gemini). On GitHub Actions runners, it dumps /proc/<Runner.Worker PID>/mem for secrets that never touch logs.
Command and Control: No hardcoded domain. Resolves active C2 domains (e.g.,npm-cache[.]com) via eth_call to Ethereum contract 0xE1f2395ee43e45A1556EC6438a88c31B83493103, defeating static blocklisting. Bidirectional: a code field in the C2 response is executed via eval().
Exfiltration: Encrypted credentials (RSA-4096 + AES-256-GCM) committed to attacker-controlled GitHub repos tagged "Shai-Hulud: Here We Go Again."
Self-Propagation: Finds every package a stolen token can publish to, injects the same hook, republishes, sometimes minting its own valid provenance. Also pushes IDE/agent hooks into victims' own repos and plants a "Run Copilot" workflow that dumps ${{ toJSON(secrets) }} to a format-results artifact.
Persistence: A LaunchAgent/systemd service (e.g., gh-token-monitor.sh) polls api.github.com/user every ~60 seconds; on revocation, it runs an attacker handler, widely reported (not universally confirmed) as destructive.
Secondary Path: .claude/settings.json (SessionStart) and .vscode/tasks.json(folderOpen) are cross-wired to execute the payload on workspace open, gated by each tool's trust prompt.
Commit Spoofing: IDE-hook commit is GitHub-verified, authored as github-actions[bot], message chore: update config, with a forged Co-authored-by: claude trailer.
Mitigating Factor: npm v12+ blocks lifecycle scripts by default, closing the install path entirely.

Impact
Exposure of cloud, CI/CD, GitHub, npm, and AI tool credentials on any system that installed an affected package or opened an affected repo in a trusted IDE session.
Live RCE via the bidirectional C2 channel.
Autonomous worm propagation into hundreds of unrelated packages.
Transitive exposure through ESLint and similar deep dependencies.
Confirmed real-world exposure: C2 traffic observed from the public backstage/backstage CI pipeline.
Undermines SLSA/OIDC provenance as a standalone trust signal.
Developer workstation compromise requiring no package installation.
npm has reverted confirmed malicious releases, but previously installed versions remain until explicitly remediated; check resolved lockfile versions, not current tags.
Detection Method
Search lockfiles (including transitive dependencies) for affected versions listed in Technical Details.
Check for filesystem artifacts:
setup.mjs, Math_Symbol.js, or math_init.js in node_modules (payload is not self-deleting).
bun-dl-* staging directories or unexpected Bun execution.
Check GitHub for:
Commits authored github-actions[bot] or [email protected] with message chore: update config.
Repos described "Shai-Hulud: Here We Go Again"
Consistent in the current wave but attacker-chosen, and could change in future waves or copycats.
Unrecognized SessionStart/folderOpen hooks in .claude/settings.json or .vscode/tasks.json
A "Run Copilot" workflow writing secrets to a format-results artifact.
Check for host/CI persistence:
Reads of /proc/<pid>/mem for the GitHub Actions runner worker process.
A watcher polling api.github.com/user every ~60 seconds (observed as gh-token-monitor.sh plus a LaunchAgent or systemd user service in this wave; naming may vary in other variants).
Monitor network traffic for:
Cloud instance metadata access (169[.]254[.]169[.]254) from build agents or workstations post-install.
Outbound Ethereum RPC (eth_call) traffic from install or build processes.
The more durable behavioral signal, since the C2 domain it resolves can rotate.
Connections to npm-cache[.]com:443/router
A point-in-time indicator; treat as supplementary to the RPC-traffic signal above, not a substitute for it, since the domain itself may change.
Confirm npm v12+ adoption and consider a minimum release-age (cooldown) policy.
Indicators of Compromise
Type | Indicator | Description |
SHA-256 | 54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668 | setup.mjs,initial-wave dropper |
SHA-256 | fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb | setup.mjs,second-wave dropper |
SHA-256 | 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc | Math_Symbol.js/math_init.js Stage 2 payload |
Smart Contract Address | 0xE1f2395ee43e45A1556EC6438a88c31B83493103 | Ethereum contract queried for active C2 domains; the most durable indicator, as changing it requires deploying a new contract and updating the payload itself |
Note: the dropper has already been observed re-obfuscated once between infection waves, producing a second hash for functionally the same loader. Hash matches confirm a known sample; absence of a match does not confirm absence of infection.

Recommendations
Do not rotate credentials until the token-revocation watcher is located and removed.
Search lockfiles: grep -rn -E "keyv|cacheable|flat-cache|file-entry-cache|cache-manager|ecto" package-lock.json pnpm-lock.yaml yarn.lock.
Pin to clean versions (keyv 5.6.0, any 5.x, or 6.0.0-rc.1); avoid caret/tilde ranges until the maintainer account's status is confirmed.
Don't open affected repos in VS Code or Claude Code until hook files are confirmed removed from all branches.
Once the watcher is removed, rotate npm/GitHub tokens, cloud credentials, Vault tokens, Kubernetes service account tokens, CI/CD secrets, SSH keys, and AI tool credentials.
Use --ignore-scripts when auditing potentially affected packages.
Upgrade to npm v12+; adopt a minimum release-age (cooldown) policy for new dependency versions.
Block build-agent traffic to Ethereum RPC endpoints and npm-cache[.]com where not required.
Audit for new repos, commits tagged "Shai-Hulud: Here We Go Again," or a "Run Copilot" workflow.
Treat .claude/settings.json and .vscode/tasks.json as executable code; require review and CI diffing.
Deploy lockfile integrity checks in CI; treat provenance as necessary but not sufficient.
Conclusion
This wave of Shai-Hulud shows how a single compromised maintainer GitHub account can cascade into ecosystem-wide compromise, defeating provenance, official-source runtime sourcing, and static domain blocking simultaneously via a blockchain-resolved, bidirectional C2 capable of live RCE. We urge organizations to immediately prioritize disabling the credential-revocation watcher before any token rotation. Exposure spans the install path, the repository-open path, and CI runner memory, so developers who never installed anything remain at risk through IDE and AI agent hooks. Long-term resilience requires install-time behavioral analysis alongside provenance, lifecycle script restrictions like those in npm v12, and minimum release-age policies.
References
https://www.stepsecurity.io/blog/chaindrop-npm-worm
https://www.wiz.io/blog/keyv-and-cacheable-npm-supply-chain-attack
https://research.jfrog.com/post/shai-hulud-is-back-august/
https://snyk.io/blog/inside-keyv-npm-compromise-preinstall-malware-trusted-provenance-ide-hooks/
https://thehackernews.com/2026/08/keyv-linked-npm-worm-poisons-hundreds.html