42 poisoned npm versions: the keyv worm containment runbook for 4 August 2026
Summary. On 4 August 2026, an attacker took over the GitHub account of the maintainer behind keyv and published malware across the keyv and cacheable npm family. Wiz Research listed 42 poisoned package versions, including keyv@6.0.0, cache-manager@7.2.10, cacheable-request@13.0.20 and @cacheable/utils@2.5.1. Aikido Security put the blast radius in download terms: keyv alone pulls roughly 127 million weekly downloads, flat-cache 565 million a month and file-entry-cache 557 million a month. The poisoned releases carried valid provenance signed by GitHub Actions, so signature checks passed. The payload steals npm tokens, GitHub CLI tokens, AWS keys and HashiCorp Vault tokens, and validates them against live APIs before exfiltration. For Indian data fiduciaries, a stolen production credential is not only an engineering problem: the Schedule to the DPDP Act, 2023 sets a ceiling of ₹250 crore for failure to take reasonable security safeguards. This is the order of operations for the first 90 minutes.
What actually shipped
Two research teams published on the same day and their package lists do not fully agree, which matters when you are grepping a lockfile.
Aikido Security's write-up, published 4 August 2026 by Ilyas Makari, names nine packages in the maintainer's own family: keyv, cacheable, cache-manager, cacheable-request, flat-cache, file-entry-cache, @cacheable/node-cache, @cacheable/memory and @cacheable/utils. Wiz Research's post, published the same morning by Merav Bar, lists 42 specific version numbers and extends well past that family into @ornikar/*, @qlik/* and @nebula.js/nucleus scopes.
Treat the union of both lists as your search set. A list that is still being updated is not a list you can diff against once and forget.
| Package | Malicious version (Wiz) | Reported install volume (Aikido) |
|---|---|---|
| keyv | 6.0.0 | ~127 million weekly downloads |
| flat-cache | not listed by Wiz | 565 million per month |
| file-entry-cache | not listed by Wiz | 557 million per month |
| cacheable-request | 13.0.20 | 133 million per month |
| @cacheable/utils | 2.5.1 | 34 million per month |
| cache-manager | 7.2.10 | 16 million per month |
| @cacheable/memory | not listed by Wiz | 28 million per month |
| @qlik/embed-react | 2.5.3 | not reported |
| @ornikar/monorepo-config | 14.3.2 | not reported |
The mechanics
Every affected package in the keyv family received two new files, setup.mjs and Math_Symbol.js, plus a "preinstall": "node setup.mjs" entry in package.json. Anyone who ran npm install against an affected version executed setup.mjs before the install finished.
setup.mjs is an obfuscated dropper. Aikido's analysis shows it downloads the Bun runtime from the bun-v1.3.13 release path on GitHub and uses that binary to run the real payload, Math_Symbol.js. Using a second runtime is a deliberate evasion choice: monitoring that watches node child processes does not see a bun process fetching and executing a script from a temp directory.
Math_Symbol.js runs a set of credential extractors. Aikido documents harvesting of npm registry auth tokens from .npmrc, GitHub CLI tokens (classic personal access tokens, session tokens and OIDC tokens) from the GitHub CLI config, AWS access keys and session tokens from ~/.aws/credentials, and HashiCorp Vault client tokens from the VAULT_TOKEN environment variable with an HTTP fallback. Extracted credentials are validated before exfiltration, so a GitHub token is checked against the live API to confirm it is active.
Wiz recorded a further evolution. Merav Bar of Wiz Research wrote on 4 August: "Wiz analysis indicates the payload is a descendant of the Shai-Hulud malware family and shares similarities with the TeamPCP and antv supply chain campaigns." The new element is command-and-control over Ethereum RPC endpoints alongside a conventional exfiltration domain, which defeats naive blocklists built only from HTTP callbacks.
Why provenance did not help
The poisoned versions were published with valid provenance attestations signed by GitHub Actions, because the attacker pushed directly to main and cut a release through the project's own workflow. The build was genuine. The source was not.
This is now a pattern, not an accident. Expel's rapid response note on the 11 May 2026 Mini Shai-Hulud wave describes the same class of abuse: the worm hijacked GitHub Actions pull_request_target triggers and extracted OIDC tokens to mint valid publish tokens, pushing malicious updates that carried SLSA Build Level 3 provenance attestations.
The engineering conclusion is unwelcome but simple. Provenance tells you which pipeline built an artefact. It does not tell you whether the commit that entered the pipeline was authorised. Treat attestation as one signal among several, not as the gate.
The first 90 minutes
Work through these four blocks in order. The order is the point: two 2026 waves shipped a dead-man's-switch that punishes teams who rotate first.
Minutes 0 to 15: find out whether you are in scope
Start with resolved versions, not declared ranges. A caret range in package.json tells you nothing; the lockfile tells you what actually installed.
# npm / pnpm / yarn: what resolved, not what was requested
grep -nE '"(keyv|cacheable|cache-manager|cacheable-request|flat-cache|file-entry-cache)"' \
package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null
# what is on disk right now, including transitive copies
find . -path '*/node_modules/keyv/package.json' -exec \
node -p "require('./{}').version" \;
# the two file artefacts, anywhere in the tree
find . -name 'setup.mjs' -o -name 'Math_Symbol.js' | head -50
ls -d /tmp/bun-dl-* 2>/dev/null
Wiz lists node_modules/keyv/Math_Symbol.js and /tmp/bun-dl-*/ as file artefacts, and npm-cache[.]com as the exfiltration domain. It also published the attribution string IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients, which is worth a grep across build logs and any quarantined payload.
For fleet-wide scanning, the open-source shai-hulud-detect script from Cobenian cross-checks more than 3,200 confirmed bad package versions across npm, PyPI, Composer and Crates, and greps for content-pattern indicators such as known-malicious file hashes, C2 domains and dead-man's-switch artefacts. It exits 0 for clean, 1 for high risk, 2 for medium risk and 3 when a per-project scan errored in bulk mode, which drops straight into a CI gate.
Minutes 15 to 30: contain before you rotate
This block is where teams get hurt. The Cobenian project's README carries an explicit warning: two waves, on 11 May and 19 May 2026, install a persistence daemon (gh-token-monitor or kitty-monitor) that wipes the host if its monitored GitHub token is revoked. The documented remediation order is to stop the persistence service first, delete its files, and only then rotate credentials.
Run the host-level check before anyone touches a token:
./shai-hulud-detector.sh --check-host ~/ # persistence artefacts in $HOME
systemctl --user list-units | grep -E 'gh-token-monitor|kitty-monitor'
launchctl list | grep -Ei 'token-monitor|kitty' # macOS equivalent
Expel's guidance from the May wave adds two more hiding places worth checking on developer machines: persistence hooks written into .vscode/tasks.json and ~/.claude/settings.json, so the payload re-executes when the editor or the coding agent starts. Editors and agent runtimes now hold the same credentials your CI does, and they are not covered by most endpoint policies.
Isolate before you clean. Pull affected build agents out of the pool, disable the affected npm automation tokens at the registry rather than deleting them, and block the published exfiltration domain at DNS.
Minutes 30 to 60: rotate in blast-radius order
Rotate by what the credential can reach, not by what is convenient. Anything reachable from a machine that ran npm install against an affected version is in scope.
| Credential | Where the payload reads it | Rotation priority | Also do |
|---|---|---|---|
| npm automation / publish token | .npmrc |
First | Audit every publish event on your own packages since 4 August |
| GitHub PAT, session and OIDC tokens | GitHub CLI config | First | Review new SSH keys, OAuth grants and workflow file changes |
| AWS access and session keys | ~/.aws/credentials |
Second | CloudTrail review for GetCallerIdentity from unknown IPs |
| HashiCorp Vault client token |
VAULT_TOKEN, HTTP fallback |
Second | Revoke leases, not just the token |
| Kubernetes and Terraform credentials | developer config paths (Wiz) | Third | Check for new service accounts and state-file access |
| Cryptocurrency wallet material | developer machines | Third | Assume loss; move funds from any hot wallet on that host |
Wiz's remediation guidance is blunt about the rebuild question: treat affected systems as potentially compromised and rebuild them if the malicious packages were installed. A cleaned laptop that once ran the dropper is a judgement call; a build runner that ran it is not. Rebuild it.
Minutes 60 to 90: re-lock, rebuild, verify
# 1. pin known-good versions explicitly, then regenerate the lockfile
npm install keyv@5.5.3 --save-exact # substitute the last version you trust
rm -rf node_modules
npm ci --ignore-scripts # no lifecycle scripts during recovery
# 2. prove the artefacts are gone
find . \( -name 'setup.mjs' -o -name 'Math_Symbol.js' \) -print
# 3. gate it in CI so a re-introduction fails the build
./shai-hulud-detector.sh --save-log shai-hulud-report.log .
npm ci --ignore-scripts is the safe recovery install. It resolves strictly from the lockfile and runs no lifecycle hooks, which is precisely the vector this campaign used. Once the tree is clean, decide whether ignore-scripts becomes your default and which packages get an explicit exception. Our note on npm 12 install script approval in CI/CD covers the approval workflow that makes that practical rather than merely aspirational.
Eleven months of the same attack
This is not the first wave and it will not be the last. Cobenian's detector tracks each one, and the scale is not improving. These are nine of the waves it catalogues.
| Wave | Date | Reported scope |
|---|---|---|
| Chalk / debug crypto theft | 8 September 2025 | 18+ packages |
| Shai-Hulud worm | 14 September 2025 | 517+ packages |
| Shai-Hulud "Second Coming" (fake Bun) | 24 November 2025 | 1,100+ packages |
| SANDWORM_MODE workflow poisoning | 17 February 2026 | 19 packages plus a GitHub Action |
| Axios RAT compromise | 31 March 2026 | axios 1.14.1 and 0.30.4 |
| Mini Shai-Hulud / TanStack | 11 May 2026 | 400+ versions, dead-man's-switch |
| Mini Shai-Hulud / AntV | 19 May 2026 | 643 versions across 323 packages |
| Miasma "Phantom Gyp" | 3 June 2026 | 57 packages, 286 versions |
| keyv / cacheable | 4 August 2026 | 42 versions listed by Wiz |
Two structural changes stand out across that sequence. The 24 November 2025 wave already used a fake Bun binary; the 4 August 2026 payload uses the real one. And the 3 June 2026 Miasma wave triggered through binding.gyp command substitution, which bypasses monitoring built solely around preinstall hooks. Any control you build against one wave's entry point ages badly.
Aaron Walton's Expel analysis of the May wave described the objective directly: "The worm is designed for lateral movement; once it infects a developer's environment, it attempts to steal AWS IAM credentials, GitHub Personal Access Tokens, HashiCorp Vault tokens, and Kubernetes secrets to compromise entire organizational infrastructures." The npm package is the delivery mechanism. Your cloud account is the target.
What to change once the incident is closed
Post-incident work splits into three controls that actually move the needle, ranked by effort against what they stop.
| Control | Stops | Effort | Ongoing cost |
|---|---|---|---|
--ignore-scripts by default plus an allowlist |
preinstall and postinstall droppers | Medium | Exceptions need review as dependencies change |
| Pinned exact versions and committed lockfiles | silent minor-version pickup of a poisoned release | Low | Renovate or Dependabot noise rises |
| Registry proxy with a quarantine window | any release younger than N days | High | Proxy operations, plus friction on urgent patches |
| Detector script as a CI gate | known bad versions and known artefacts | Low | List updates lag each new wave by hours |
| Short-lived OIDC credentials in CI | reuse of a stolen long-lived token | Medium | Requires rework of every workflow that publishes |
The last row is the one that changes the economics. A stolen static token is useful for weeks; a stolen 15-minute OIDC token is usually worthless by the time it is exfiltrated and validated. Our guide to npm OIDC trusted publishing and cache poisoning hardening walks through that migration for a publishing pipeline, and Dependabot malware alerts across npm and PyPI covers the detection side. Teams rebuilding their front-end platform after an incident like this should also read our web platform developer guide for where dependency policy fits in the wider stack.
A quarantine window deserves a specific word. Both Aikido and Wiz published within hours of the malicious releases going live on 4 August. A registry proxy that refuses any package version younger than 24 or 48 hours would have blocked this compromise for most consumers at zero incident cost. The trade is real: you cannot pull an urgent security patch on day zero either. For teams that ship several times a day, a 24-hour window on transitive dependencies with an explicit break-glass path is the version of this control that survives contact with delivery pressure.
India-specific considerations
Indian engineering teams carry an extra obligation here, and the arithmetic is unforgiving.
Under the Digital Personal Data Protection Act, 2023, penalties are fixed rupee ceilings set out in the Schedule rather than a percentage of turnover, and they are assessed per instance. Failure to take reasonable security safeguards to prevent a personal data breach carries a ceiling of ₹250 crore. Failure to notify the Data Protection Board of India and affected users of a breach carries ₹200 crore. A single incident that breaches several obligations compounds.
That reframes the question a CTO in Gurugram or Bengaluru should be asking. It is not "did the malware run" but "can we demonstrate, with evidence, what it could reach and what we did about it within a defensible window". Three artefacts make that demonstrable: a lockfile-based inventory that proves which versions resolved on which date, a credential map that shows what each rotated token could access, and a timestamped remediation log. Teams building that evidence chain from scratch will find the sequencing in our DPDP Act engineering playbook.
Indian product teams working with global customers face a second demand: the customer's own incident questionnaire. Buyers under SOC 2 or ISO 27001 scope will ask for your affected-version list, your rotation timestamps and your CI evidence, usually within days. Assembling those after the fact costs more engineering hours than the containment itself.
FAQ
Which npm packages were compromised on 4 August 2026?
Wiz Research listed 42 poisoned versions including keyv 6.0.0, cache-manager 7.2.10, cacheable-request 13.0.20 and @cacheable/utils 2.5.1, plus packages in the @ornikar and @qlik scopes. Aikido Security named nine packages in the maintainer's family, adding flat-cache, file-entry-cache, @cacheable/memory and @cacheable/node-cache to that set.
How do I check whether my project installed a poisoned version?
Search your lockfile rather than package.json, because declared ranges do not tell you what resolved. Then look on disk for the file artefacts: setup.mjs and Math_Symbol.js anywhere under node_modules, plus any /tmp/bun-dl-* directory. The open-source shai-hulud-detect script automates both checks across an entire directory tree.
Why should I not rotate my tokens immediately?
Two 2026 waves, on 11 May and 19 May, installed a persistence daemon named gh-token-monitor or kitty-monitor that wipes the host if the GitHub token it watches is revoked. The documented order is to stop that service, delete its files, and only then rotate. Check for the daemon before touching any credential.
Did package provenance stop this attack?
No. The attacker pushed directly to the main branch and cut a release through the project's own GitHub Actions workflow, so the poisoned versions carried valid provenance signed by GitHub Actions. Provenance proves which pipeline built an artefact. It does not prove the commit entering that pipeline was authorised by the maintainer.
What credentials does the payload steal?
Aikido documented harvesting of npm registry tokens from .npmrc, GitHub CLI tokens including classic personal access tokens and OIDC tokens, AWS access and session keys from the credentials file, and HashiCorp Vault tokens from the VAULT_TOKEN variable. Wiz adds Kubernetes configurations, Terraform credentials, AI configuration files and cryptocurrency wallets.
Does npm ci with ignore-scripts fully protect me?
It blocks this specific entry point, because the payload ran through a preinstall lifecycle hook. It does not block every technique: the Miasma wave of 3 June 2026 triggered through binding.gyp command substitution, which bypasses monitoring built only around preinstall and postinstall hooks. Combine it with pinned versions and a CI detector gate.
What does this cost an Indian company that leaks customer data?
Under the Schedule to the DPDP Act, 2023, failure to take reasonable security safeguards to prevent a personal data breach carries a ceiling of ₹250 crore, and failure to notify the Data Protection Board and affected users carries ₹200 crore. Penalties are fixed rupee amounts assessed per instance rather than a share of turnover.
Should we rebuild affected machines or just clean them?
Wiz's guidance is to treat affected systems as potentially compromised and rebuild them if the malicious packages were installed. For CI runners and build agents, rebuild without debate: they hold the widest credential set and are cheap to replace. For developer laptops, rebuild any host where the persistence artefacts or the dropper were actually found.
How eCorpIT can help
eCorpIT builds and hardens delivery pipelines for product teams in India and abroad, and supply-chain incidents like this one are a delivery-engineering problem before they are a security one. Our senior engineering teams work on lockfile discipline, install-script policy, OIDC-based publishing and CI gating, and we design applications aligned with DPDP Act requirements for evidence and breach notification. We are CMMI Level 5, MSME certified and ISO 27001:2022 certified. If you need help working through an affected dependency tree or rebuilding your publishing pipeline so the next wave cannot reach production, talk to our engineering team.
References
- Keyv and friends compromised in active Shai-Hulud supply chain attack — Aikido Security, Ilyas Makari, 4 August 2026.
- keyv and cacheable npm package hijacked in supply chain attack — Wiz Research, Merav Bar, 4 August 2026.
- Mini Shai Hulud: cross-ecosystem supply chain worm targeting npm and PyPI — Expel, Aaron Walton, 12 May 2026.
- Cobenian/shai-hulud-detect — open-source detector, compromised-package list and wave history.
- Mini Shai-Hulud worm compromises TanStack, Mistral AI and more — The Hacker News, May 2026.
- TanStack npm packages hit by Mini Shai-Hulud — Snyk.
- Mini Shai-Hulud hits AntV: 300+ malicious npm packages — Snyk.
- The npm threat landscape: attack surface and mitigations — Unit 42, Palo Alto Networks.
- Shai-Hulud 2.0 npm worm: analysis and what you need to know — Datadog Security Labs.
- Penalties and adjudication under India's DPDP Act, 2023 — King Stubb & Kasiva.
- Mass supply chain attack hits TanStack and Mistral AI on npm and PyPI — SafeDep.
- npm supply chain security in 2026: what your package manager does and does not protect you from — Mondoo.
Last updated: 4 August 2026.
Top comments (0)