A compromised maintainer account turned five of the npm ecosystem's most deeply embedded caching libraries into a credential-stealing worm on August 4, 2026, and by the afternoon the compromise had spread to hundreds of unrelated packages.
Compromised keyv Maintainer Account Triggers August 4 Publish Burst
Socket's Threat Research Team and Aikido Security both identified the same maintainer account, "jaredwray," as the entry point. That account controls keyv, a key-value storage abstraction with adapters for Redis, SQLite, Postgres, and MongoDB, alongside the cacheable family of caching utilities that sit as transitive dependencies deep inside common tooling such as ESLint. keyv@6.0.0 was published at 14:05 UTC carrying a malicious preinstall hook. Roughly ninety minutes later, between 15:39 and 15:44 UTC, nine cacheable-family packages followed in a rapid burst. The jaredwray/keyv GitHub repository showed force pushes to main, repeated deletion of the v6.0.0 release tag, and a commit explicitly titled to add the malicious files to every @keyv/* package — signs that the attacker retained working account and CI access rather than making a single opportunistic push. Aikido's follow-up update, timestamped 13:37 CEST the same day, reported the worm had already reached at least 434 packages across 1,381 versions with a combined total exceeding 2 billion monthly installs.
Preinstall Hook Chain: setup.mjs, a Downloaded Bun Runtime, and the Math\_Symbol.js Payload
The compromise lives entirely in the npm install lifecycle rather than in the library code itself. Socket's technical breakdown found the shipped dist/ output byte-identical to the last clean release; the trojanized package.json simply adds setup.mjs and Math_Symbol.js to the published files and wires a "preinstall": "node setup.mjs" hook, so the package behaves normally once installed while the host is already compromised. setup.mjs detects the operating system and architecture — including Alpine and musl builds via ldd --version and /etc/os-release — then downloads a matching standalone Bun v1.3.13 runtime and uses it to execute the second stage, sidestepping the host's own Node version and any Node-level monitoring.
That second stage, Math_Symbol.js (also observed under the name math_init.js), is a roughly 728 KB obfuscated Bun bundle. Its credential collector targets a wide surface: AWS instance metadata and Secrets Manager across regions, GCP service account keys, Azure client secrets, HashiCorp Vault tokens pulled from six separate source paths, Kubernetes service account tokens, GitHub Actions OIDC request tokens, and npm tokens validated live against the registry's whoami endpoint — plus a roughly 200-pattern filesystem sweep for .env files, SSH keys, Terraform state, and Docker credentials, according to Aikido's IOC analysis. Where the worm finds a usable npm identity, it queries the registry for other packages that maintainer controls, mints a fresh publish credential through npm's OIDC token-exchange endpoint, and republishes those packages with the same hook — which is how the compromise turned from a single-account incident into a self-propagating worm. Because OIDC trusted publishing signs whatever the pipeline produces, republished versions can inherit valid provenance; signature verification alone did not catch the initial keyv@6.0.0 release either, since the build pipeline faithfully attested a source that was already trojanized.
Download Exposure Across the keyv and Cacheable Package Family
What makes the blast radius unusual is how rarely developers install these packages directly. keyv, flat-cache, and file-entry-cache are foundational utilities that appear deep in dependency trees — as transitive dependencies of tools like ESLint, for example — which is exactly why most affected environments never chose to add them. Aikido's per-package download figures, drawn from npm registry data, show the top three compromised packages alone accounting for well over half a billion monthly downloads each.
Full List of Compromised Packages, Versions, and Registry Links
The list below combines Socket's and Aikido's independently published package/version data. Both trackers describe their lists as ongoing at time of publication — Wiz Research's IOC dataset maintains a broader enumeration of the keyv-ecosystem packages that developers should check against directly, since automated tools could not retrieve its raw contents for reproduction here.
| Package | Compromised Version | Reported Monthly Downloads | Confirmed By |
|---|---|---|---|
keyv | 6.0.0 | ~604M | Socket, Aikido |
flat-cache | 6.1.24 | ~580M | Socket, Aikido |
file-entry-cache | 11.1.6 | ~571M | Aikido |
cacheable-request | 13.0.20 | ~137M | Socket, Aikido |
@cacheable/utils | 2.5.1 | ~34M | Aikido |
cacheable | 2.5.1 | ~30M | Socket, Aikido |
@cacheable/memory | 2.2.1 | ~28M | Socket, Aikido |
cache-manager | 7.2.10 | ~16M | Socket, Aikido |
@cacheable/node-cache | 3.1.2 | ~6M | Socket, Aikido |
ecto | 5.0.1 | ~4.5K | Aikido |
@cacheable/net | 2.1.1 | ~3.7K | Socket, Aikido |
@thiennq/docs-viewer | 1.6.2 | not disclosed | Socket |
Confirmed downstream / worm-spread packages (a partial example set out of the 434 packages Aikido reported; check the Wiz IOC CSV or your registry proxy logs for the full list):
| Package | Compromised Version |
|---|---|
@deliveroo/reevent | 1.0.1 |
@or-sdk/invitations | 1.4.9 |
@picsart/ai-sdk | 3.32.2 |
@qlik/embed-runtime | 1.6.4 |
picasso.js | 2.11.6 |
Indicators of compromise (Aikido Security):
| Artifact | SHA-256 |
|---|---|
| setup.mjs | 54dc7ea54a1317cca0e890a2770630cf7fa6c97813e0cb9d2caa93012b350668 |
| setup.mjs (community-spread variant) | fd3ca4007b225fdf8de7af4345a19179d5efa8c4bb9205f88cda806e5684b1eb |
| Math_Symbol.js / math_init.js | 9fc2570b7cef51c1b8df116d144d11ff4096357be7d2c4c6367cfc2509cf1bcc |
Network IOC: npm-cache[.]com:443/router (fallback exfiltration endpoint; domain registered 2026-05-22). GitHub IOC: any repository whose description contains the string "Shai-Hulud: Here We Go Again" — these are attacker-controlled exfiltration drop points, not legitimate forks of the project.
Self-Propagation Beyond the Original Maintainer and What Remains Unconfirmed
The worm's spread to organization-owned packages like @deliveroo/reevent and @qlik/embed-runtime shows the self-propagation mechanism working as designed — a compromised npm token on any downstream project can extend the campaign regardless of whether that project's own maintainers did anything wrong. This is the same persistence pattern Bytepith covered in an earlier npm supply chain compromise in the TanStack ecosystem and echoes the developer-tooling persistence angle from a related campaign that used a poisoned VS Code extension: the .claude/settings.json and .vscode/tasks.json autostart hooks planted in the source repository mean simply cloning the code, without ever running npm install, can trigger the loader for a developer or an AI coding agent that opens the folder.
What is not yet settled: the exact final count of affected packages and versions, since both Socket and Aikido describe their trackers as live and expanding; whether the maintainer's credentials were phished, reused, or extracted through a separate breach; and how many of the roughly 1,300 exfiltration repositories Aikido observed have since been taken down by GitHub. Treat any environment that installed an affected version and allowed install scripts to run as compromised, rotate rather than merely refresh every credential reachable from that host, and pin dependency versions with integrity hashes rather than caret or tilde ranges while the investigation continues.





Comments (1)
Please sign in to join the discussion.