
NPM Malware Compromises keyv and cacheable with 500M+ Weekly Downloads and Spreads to Hundreds of Packages | Blog | Endor Labs
Endor Labs' active-tracking advisory on an npm supply-chain worm that compromised keyv, flat-cache, and file-entry-cache (500M+ combined weekly downloads) via the jaredwray/Cacheable GitHub Actions OIDC trusted-publishing pipeline, injecting a preinstall hook (setup.mjs) that fetches a legitimate Bun binary to run an obfuscated ~727KB stage-2 payload (Math_Symbol.js/math_init.js) stealing AWS, npm, GitHub, and Vault tokens. The stolen tokens were used to self-propagate the same payload to 384+ packages and 1,136+ versions across unrelated maintainer accounts, including scopes belonging to companies like ServiceTitan, Qlik, and Picsart. The post includes IOCs (file hashes), affected package/version lists, and mitigation guidance (lockfile/CI log checks, --ignore-scripts).
What it is
An initial advisory (August 4, 2026) on an active, worming npm credential-stealer seeded in the jaredwray/Cacheable ecosystem and now republished across hundreds of unrelated packages. This document carries the operational details the summary omits: detection, mitigation, and indicators.
How it works
Every malicious version injects "scripts": { "preinstall": "node setup.mjs" }, so the payload runs at npm install time — including for transitive and dev-only dependencies. setup.mjs is an obfuscated dropper that downloads an unmodified Bun 1.3.13 binary from official GitHub releases, then uses Bun to run a ~727 KB obfuscated stage-2 payload shipped inside the package (Math_Symbol.js in the first wave, math_init.js later — the two files are byte-identical). Bringing its own runtime means the only stage-1 network fetch is a legitimate Bun release, with no attacker download domain to block. Stage 2 harvests AWS credentials, npm tokens, GitHub tokens (including ghs_ Actions/App tokens), and HashiCorp Vault tokens, then self-propagates by publishing new malicious versions with stolen tokens — mostly CI/service-account tokens harvested from build runners that had themselves installed a poisoned dependency.
Preconditions / Affected
- Any
npm install(without--ignore-scripts) that resolves an affected version. flat-cacheandfile-entry-cachesit in the ESLint dependency chain, so many projects pull them transitively even as dev dependencies — this does not reduce risk.- First-wave tarballs carry valid npm signatures and SLSA provenance (published through the legitimate OIDC pipeline); later republishes under stolen tokens have no provenance.
- Abused scopes include
@servicetitan/*,@ornikar/*,@onereach/*,@or-sdk/*,@qlik/*,@nebula.js/*,@hubsync/*,@picsart/*,@arv-bedrock/*,@adminide-stack/*— via stolen tokens, not company-system compromise.
What to do
- Do not trust "latest looks clean." Many bad versions have been unpublished, so a current lockfile resolving to a safe version does not mean you never installed a poisoned one. Audit historical lockfiles and CI logs.
- Pin/force safe versions with
overridesforkeyv,flat-cache,file-entry-cache. - Install with
--ignore-scriptswhere feasible to neutralize thepreinstallhook. - Hunt for
setup.mjs, apreinstallrunningnode setup.mjs,bun-dl-*artifacts, and the stage-2 filenames. - Rotate any AWS, npm, GitHub, and Vault credentials reachable from affected build environments.
Indicators (SHA-256):
9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc Math_Symbol.js / math_init.js
54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668 setup.mjs
fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb setup.mjsCaveats
Point-in-time snapshot for August 4, 2026. The verified 384 packages / 1,136 versions are explicitly a floor — versions are being unpublished and new ones keep appearing. Payload analysis is described as "initial"; a fuller technical write-up of the loader and worming behavior is promised in a follow-up.
Organisations named here
- math_init.js
- Math_Symbol.js
- ServiceTitan
- setup.mjs
Technologies named here
- Endor Labs
- keyv
- Bun 1.3.13
- flat-cache
- file-entry-cache
- @servicetitan/*
- @ornikar/*
- @onereach/*
- @or-sdk/*
- @qlik/*
- @nebula.js/*
- @hubsync/*
- @picsart/*
- @arv-bedrock/*
- @adminide-stack/*
- 384 verified packages / 1,136 malicious versions
- npm
- Bun
- GitHub Actions
- OIDC
- AWS
- Vault
- cacheable
- SLSA
Techniques named here
- Malicious npm preinstall script
- Trusted publishing pipeline abuse
- Stolen npm publishing token abuse
- Living-off-legitimate-binary execution
- Credential theft / stealer
- Self-propagation / worming via npm publish
Threat actors named here
- npm keyv/cacheable supply chain compromise campaign
Related in Supply Chain


