Keyv/Cacheable npm Compromise: Mini Shai-Hulud Worm Poisons Hundreds of Packages via preinstall Hook and Claude Code/VS Code Autostart
On 4 August 2026, the release pipeline for keyv (619M downloads/month per Snyk) and roughly a dozen related packages from the cacheable ecosystem was compromised. A newly inserted preinstall hook loads an encrypted Bun-runtime payload (Math_Symbol.js, about 728 KB) that harvests cloud (AWS/GCP/Azure), CI/CD, npm, and GitHub credentials. The worm self-propagates by using stolen publish tokens, and thanks to npm's Trusted Publishing attestation it even produces cryptographically “genuine” signed malicious releases. It also drops autostart hooks into .claude/settings.json and .vscode/tasks.json — code then runs the moment a cloned repo is opened in Claude Code or VS Code, without any npm install. Snyk tracks the incident as SNYK-JS-KEYV-18515941 (Critical); no official CVE number had been assigned at the time of this article.
TL;DR — 90 seconds
- Affected?
Projects with a direct or transitive dependency on
keyv@6.0.0,cacheable@2.5.1,cacheable-request@13.0.20,flat-cache@6.1.24,file-entry-cache@11.1.6,cache-manager@7.2.10, and several scoped@cacheable/*packages (includingnet,node-cache,memory).flat-cache/file-entry-cachereach many teams indirectly via ESLint.- Risk?
Critical. A
preinstallhook runs code with developer/CI privileges on a plainnpm install, downloads an encrypted Bun payload, and harvests cloud, CI/CD, and registry credentials. The worm also plants autostart hooks in.claude/settings.jsonand.vscode/tasks.jsonthat trigger simply by opening a cloned repo — even without installation.- Immediate action?
Pin affected packages to last-known-clean versions via
overrides/resolutions, rebuild lockfiles without executing scripts (--ignore-scripts), and check for the documented IOCs — before rotating tokens (the worm watches for token revocation and triggers additional payloads when it happens).- Recommendation?
Every team with a Node.js/npm build or CI pipeline should check its dependency tree against the affected packages immediately — including transitively, even if none of the top-level dependencies look directly affected.
- Criticality?
critical — an active, self-propagating supply-chain worm with credential theft, IDE persistence, and an anti-forensics mechanism against token rotation.
What is the problem?
According to converging analysis from Snyk, Socket.dev, Cloudsmith, Wiz, and other vendors, the release pipeline for keyv — maintained by jaredwray — was compromised on 4 August 2026. Per Snyk's reconstruction, malicious commits landed in the keyv repository around 09:02–09:17 UTC, adding a preinstall script hook ("preinstall": "node setup.mjs") along with the associated payload files. At 09:35 UTC, keyv@6.0.0 was published to npm with this hook — including a valid npm provenance attestation, since the build process itself was unmodified and ran legitimately via GitHub Actions. That's the central point: npm provenance attests that a given workflow built an artifact — not that the source code fed into that workflow is trustworthy. If the maintainer account, repo access, or CI credentials were compromised before publication, provenance signs a malicious artifact just as readily as a clean one.
The preinstall hook loads a roughly 29.9 KB loader (setup.mjs) that detects platform and architecture, downloads a standalone Bun runtime, and uses it to run a roughly 728 KB, polymorphically base91-encoded second stage (Math_Symbol.js) — outside the usual Node-based monitoring paths. Between 10:09 and 10:14 UTC the cacheable family followed, then further packages such as ecto@5.0.1 (10:28 UTC). The worm self-propagates: it searches for further packages by the compromised maintainer(s), injects the same preinstall hook, recomputes integrity/shasum fields, bumps the version, and republishes via npm's Trusted Publishing — so follow-on releases also carry valid attestations.
A second trigger path, independent of the install step, makes this incident particularly notable: the compromised repository additionally contains .claude/settings.json with a SessionStart hook and .vscode/tasks.json with a runOn: "folderOpen" task, each invoking its own setup.mjs. If an affected repository is merely opened in Claude Code or VS Code — no npm install, no build — the loader still runs. That means simply cloning and opening a repo is already an infection path in this incident, not just installing it as a dependency.
Who is affected?
| Package | Poisoned version | Last clean version |
|---|---|---|
keyv | 6.0.0 | 5.6.0 |
cacheable | 2.5.1 | 2.5.0 (verify the last version before the incident) |
cacheable-request | 13.0.20 | 13.0.19 (verify the last version before the incident) |
flat-cache | 6.1.24 | 6.1.23 |
file-entry-cache | 11.1.6 | 11.1.5 |
cache-manager | 7.2.10 | 7.2.9 |
@cacheable/net, @cacheable/node-cache, @cacheable/memory and other scoped packages | varies by package, see Snyk advisory SNYK-JS-KEYV-18515941 | last version before the incident |
Particularly relevant for TYPO3/PHP teams: flat-cache and file-entry-cache reach many projects not as a direct dependency but transitively via ESLint in the frontend build (e.g. TYPO3 sitepackages with an npm-based asset build). A plain npm ls without --all will miss such transitive hits. The exact, complete package list is still evolving as the investigation continues — the current version of Snyk advisory SNYK-JS-KEYV-18515941 and the Socket.dev and Wiz analyses are authoritative.
Impact
Per Snyk and Socket.dev, the payload targets credentials broadly: GitHub and npm tokens, cloud credentials (AWS metadata via IMDSv1/v2, GCP service-account keys, Azure client secrets), HashiCorp Vault tokens, Kubernetes service-account tokens, SSH keys, TLS certificates, database connection strings, and GitHub Actions runner memory (including OIDC tokens and repository secrets). Exfiltration happens via newly created public GitHub repositories and DNS tunneling, among other channels.
Particularly concerning is a documented persistence mechanism (“gh-token-monitor”) that watches stolen GitHub tokens: if a token is revoked, the mechanism executes an attacker-supplied handler — turning the usual “contain, then rotate” incident-response order against defenders. Rotating tokens before removing this persistence can potentially trigger an additional, actively fired malicious-code path.
Because the worm self-propagates via stolen publish tokens while still obtaining valid npm provenance attestations, a trust model based purely on signature verification fails here: “cryptographically signed” explicitly does not mean “trustworthy source code” in this case. Affected are not only production environments but also developer laptops and CI runners — anywhere one of the packages was installed or an affected repository was opened.
Mitigation / immediate measures
Operational decision block
- Act now if … one of the affected packages (direct or transitive, e.g. via ESLint) appears in your dependency tree — production and development/CI environments.
- Check with priority if … repositories were cloned or opened in Claude Code/VS Code in the last few days without a dependency scan running.
- Watch if … none of the packages appear in your tree — the package list is still evolving as the investigation continues, so a repeat scan over the coming days is worthwhile.
Step 1 — pin affected packages to clean versions
{
"overrides": {
"keyv": "5.6.0",
"cacheable": "2.5.0",
"cacheable-request": "13.0.19",
"flat-cache": "6.1.23",
"file-entry-cache": "11.1.5",
"cache-manager": "7.2.9"
}
}
// package.json ("overrides" for npm; use "resolutions" for Yarn)
Step 2 — rebuild the lockfile without executing scripts
npm install --package-lock-only --ignore-scripts
rm -rf node_modules
npm cache clean --force
npm ci --ignore-scripts
Step 3 — remove persistence before rotating tokens
# hunt for the gh-token-monitor persistence mechanism:
ls -la ~/.local/bin/ ~/.config/gh-token-monitor/ \
~/.config/systemd/user/ 2>/dev/null
ls -la ~/Library/LaunchAgents/ 2>/dev/null # macOS
# take a forensic copy, then remove the persistence
# (stop/disable the systemd unit or unload the LaunchAgent),
# only then proceed to step 4
Step 4 — rotate credentials
# GitHub token: revoke and reissue
# npm token: revoke (npm token revoke) and reissue
# Also rotate cloud keys (AWS/GCP/Azure), Vault tokens, Kubernetes
# service-account tokens, SSH keys, and database connection strings
# if an affected machine/CI runner had the packages installedDetection / verification
Check the dependency tree (including transitively)
npm ls keyv flat-cache file-entry-cache cacheable-request \
cacheable cache-manager @cacheable/net @cacheable/node-cache \
@cacheable/memory --all
Hunt for known payload files and IOCs
find "$HOME" /tmp -name setup.mjs -o -name Math_Symbol.js \
-o -name gh-token-monitor.sh -o -name gh-token-monitor.service \
-o -name com.user.gh-token-monitor.plist 2>/dev/null
# check the process chain: node setup.mjs spawning a downloaded
# bun binary; look for temp directories matching "bun-dl-*"
find /tmp -maxdepth 2 -iname "bun-dl-*" 2>/dev/null
Find compromised preinstall hooks in the node_modules tree
find node_modules -name package.json -print0 | xargs -0 node -e '
const fs = require("node:fs");
for (const file of process.argv.slice(1)) {
try {
const pkg = JSON.parse(fs.readFileSync(file, "utf8"));
if (pkg.scripts?.preinstall === "node setup.mjs") {
console.log(`${pkg.name}@${pkg.version}`);
}
} catch {}
}
'
Check IDE/editor autostart hooks
# in every cloned repository, check whether these files exist and
# contain suspicious setup.mjs invocations:
git -C /path/to/repo show HEAD:.claude/settings.json 2>/dev/null
git -C /path/to/repo show HEAD:.vscode/tasks.json 2>/dev/null | grep -A3 folderOpen
Check CI/CD and cloud audit logs
- npm account: check for unexpected publishes on/after 4 August 2026 (
npm profile get, the audit log in the npm account dashboard). - GitHub: check for newly created, unfamiliar public repositories in your account/org (a typical exfiltration target of this worm).
- Cloud providers: check CloudTrail/audit logs for unusual API calls from build agents/CI runners over the last few days.
Operator guidance
Mid-market
Check the dependency tree of every active Node.js/npm project (including frontend build toolchains such as TYPO3 sitepackages with ESLint) today against the affected package list. Rebuild lockfiles without executing scripts, check for the persistence mechanism, and only then rotate tokens.
Enterprise / multi-repo
Run a centralized scan across all repositories and CI pipelines (SCA tooling or the npm ls --all command above per project), including developer laptops where affected repos were cloned/opened — not just CI. Because the worm propagates via legitimate, attested releases, signature verification alone is not enough; version pins/overrides are mandatory until the affected package list is considered final.
Teams using AI coding tools (Claude Code, Cursor, VS Code)
Specifically check every repository cloned or opened in the last few days for .claude/settings.json and .vscode/tasks.json with folderOpen/SessionStart hooks — this infection path fires regardless of whether npm install was ever run.
Decision block
Act today if: one of the affected packages was found in your tree, or a repo was opened/cloned in the last few days. This week if: Node.js/npm toolchains are in use but no scan has run yet. Watch if: pure PHP/TYPO3 backends without an npm-based frontend build — vigilance is still worthwhile here, since the package list is still evolving.
What I did concretely
I treat npm supply-chain worms as a pipeline-discipline question, not a question about a single bad package. For my own and client projects with an npm-based frontend build (including TYPO3 sitepackages), I checked the dependency tree against the package list above, verified --ignore-scripts as the standard for CI installs, and updated the Renovate configuration to explicitly block the affected versions until the advisory situation settles. I also spot-checked cloned repositories for .claude/settings.json or .vscode/tasks.json files with unusual autostart hooks — with a negative result, but that check now belongs in my standard routine whenever opening someone else's repository, not just when installing it.
Frequently asked questions about the Keyv/Cacheable npm worm
How can a signed npm package be malicious?+
npm's Trusted Publishing attestation proves that a given GitHub Actions workflow built the published artifact — not that the source code fed into that workflow is trustworthy. If the maintainer account or repo access was compromised before publication, provenance signs a malicious artifact just as readily as a clean one.
Is npm install --ignore-scripts enough protection?+
Against the preinstall-hook path, yes — --ignore-scripts prevents the loader from running on install. It doesn't help against the second infection path via .claude/settings.json and .vscode/tasks.json: that one fires as soon as the repo is opened in Claude Code or VS Code, regardless of npm install.
Why remove persistence first and only then rotate tokens?+
Because a documented persistence mechanism (“gh-token-monitor”) watches stolen GitHub tokens and, on revocation, executes an attacker-supplied handler. Rotating first can trigger exactly that additional malicious-code path — the usual incident-response order is deliberately turned against defenders here.
Is this the same as the binding.gyp worm from June 2026?+
No, but it belongs to the same family of self-propagating npm supply-chain worms (the “Shai-Hulud” lineage) we've covered here before — for example the TanStack incident CVE-2026-45321 or Miasma. Affected packages, payload, and trigger paths differ each time; the underlying tactic (lifecycle hook, credential harvesting, automatic self-propagation) is similar.
Does this affect me if I only run PHP/TYPO3 without npm?+
Not directly if your project has no npm dependencies. But a great many TYPO3 sitepackages build their frontend assets through npm-based toolchains (Webpack, Vite, ESLint) — and that's exactly where flat-cache/file-entry-cache frequently land transitively via ESLint. Running npm ls --all inside the sitepackage directory will tell you.
Is there a CVE number yet?+
Not at the time of this article. Snyk tracks the incident under its own advisory ID SNYK-JS-KEYV-18515941 (rated Critical, CWE-506 — Embedded Malicious Code). An official CVE assignment may still follow; until then, the Snyk advisory is the authoritative, continuously updated reference.
Conclusion
The Keyv/Cacheable incident joins an already long series of self-propagating npm worms from the “Shai-Hulud” family — two aspects here are new and notable. First, the worm abuses npm's Trusted Publishing attestation to get its own malicious releases cryptographically signed as “genuine,” showing that provenance verification alone does not detect compromised source-code pipelines. Second, it extends the infection path beyond the classic npm install boundary into IDE autostart hooks (Claude Code, VS Code) — simply opening a cloned repo is enough. Anyone running Node.js/npm toolchains should check their dependency tree, rebuild lockfiles without executing scripts, and start treating repository-local editor configuration files as part of the attack surface going forward — not just package.json.
Sources
- Snyk — Inside the keyv npm Supply Chain Compromise (SNYK-JS-KEYV-18515941)
- Socket.dev — Popular npm packages in the keyv and cacheable namespaces compromised
- Cloudsmith — Keyv and Cacheable npm Packages Compromised in Active Supply-Chain Attack
- Wiz — keyv and cacheable npm Package Hijacked in Supply Chain Attack
- The Hacker News — Keyv-Linked npm Worm Poisons Hundreds of Packages, Plants Claude Code and VS Code Hooks
- SafeDep — npm Worm Poisons 400+ Packages Across Nine Organisations
- Aikido — Keyv and friends compromised in npm supply chain attack
I check, mitigate, and validate your npm/CI supply chain against worms like the Keyv/Cacheable incident.
Dependency-tree audit against affected packages, lockfile rebuilds without script execution, Renovate/CI hardening against compromised Trusted Publishing releases, and review of repository-local editor autostart hooks.
Platform operations, not paper consulting: I continuously review, patch, and harden your software supply chain.
About the author
![[Translate to English:] Foto von Kai Ole Hartwig.](/fileadmin/_processed_/e/9/csm_ole-neu_73323ad80d.jpeg)
Kai Ole Hartwig
Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.