// threat brief

No CVE ID

keyv, cacheable and other npm caching packages hijacked: install-time credential theft that spread itself to hundreds of packages (Shai-Hulud / ChainDrop)

CVSS
—
CISA KEV
Not listed
Weakness
CWE-506

PlainCVE Team · Published 2026-09-30 · AI-assisted · Press brief ↓

AI review 2026-09-30 (not human-reviewed)Command tests: none yetReproduced: not yetVerification record ↓

Hijacked releases of keyv, flat-cache and other npm caching packages ran credential-stealing malware at install time and spread to 400+ packages.

Who is affectedDeveloper machines and CI environments that installed or updated to the malicious versions, such as keyv 6.0.0, flat-cache 6.1.24, file-entry-cache 11.1.6, cacheable 2.5.1, cacheable-request 13.0.20 and cache-manager 7.2.10, or an infected downstream package, where install scripts ran during the install (installing with --ignore-scripts or with npm v12 defaults does not trigger it). The bad versions were published on 2026-08-04, but later installs could still pull them through downstream packages not yet removed, private registries / mirrors, or caches (our inference; Snyk advises purging these versions from private registries and caches). Also anyone who opened a repository with planted config files; OSV says the loader runs when a developer or AI coding agent opens a clone, while Snyk says the developer or agent has to trust and activate the project config (VS Code may ask first, depending on workspace trust and user settings).
What happensThe malware runs automatically during npm install, steals cloud, GitHub, npm and Kubernetes credentials and private keys, and uses stolen npm tokens to infect more packages (OSV). Researchers add that it looks for database credentials (SafeDep, Snyk) and installs a gh-token-monitor watcher that runs an attacker handler when a stolen token is revoked (SafeDep, Snyk, Wiz); Wiz says this dead-man's switch is armed selectively based on the attacker server's response.
What to do nowCheck lockfiles and node_modules for these versions. If present, treat the machine as compromised. GitHub's advisory says to rotate all secrets immediately from a different computer; based on warnings from Socket, Snyk and Chainguard, our recommended order is: isolate the machine and remove the gh-token-monitor persistence first, then rotate every credential from a clean computer, then rebuild. Pin known-good versions and reinstall with npm ci --ignore-scripts.
Affected versionskeyv 6.0.0, flat-cache 6.1.24, file-entry-cache 11.1.6, cacheable 2.5.1, cacheable-request 13.0.20, cache-manager 7.2.10, @cacheable/net 2.1.1, @cacheable/node-cache 3.1.2, @cacheable/memory 2.2.1, @cacheable/utils 2.5.1, ecto 5.0.1, plus 400+ downstream packages later infected by the worm; OSV and GHSA also list version 6.0.0 of 19 @keyv/* adapter packages as malicious (Socket says those versions lack the preinstall hook, and Chainguard says @keyv/* was never affected)
Fixed versionsThere is no "patched" version; use the release before the malicious one, e.g. keyv 5.6.0, flat-cache 6.1.23, file-entry-cache 11.1.5, cacheable-request 13.0.19, cache-manager 7.2.9, ecto 5.0.0 (Snyk), or any version published before 2026-08-04 09:30 UTC (Endor Labs)
Timeline
  • Introduced 2026-08-04 · Malicious keyv@6.0.0 published to npm source
  • First public 2026-08-04
  • First attacks 2026-08-04 · Socket detected it about 6 minutes after keyv@6.0.0 was published; by 09:38 UTC it had spread to packages under other accounts source

Blue team playbook

Check, fix / mitigate, respond, harden. Matching the affected versions does not mean you were compromised, and a check that finds nothing does not prove you are safe; each item says what it can and cannot show. Tagged steps point to where the attack flow below can be stopped.

DETECTCheckAm I affected? Any signs of compromise?
  1. 01Check your dependency tree and lockfiles

    List the versions actually installed and search package-lock, yarn.lock and pnpm-lock for the affected versions. Include indirect dependencies, the downstream packages named in the advisories, and the 6.0.0 release of the @keyv/* adapter packages.

    Read-only check
    npm ls keyv flat-cache file-entry-cache cacheable cacheable-request cache-manager ecto @cacheable/net @cacheable/node-cache @cacheable/memory @cacheable/utils --all
  2. 02Look for the loader and second-stage files

    Search node_modules for packages whose preinstall runs setup.mjs, and for files named setup.mjs or Math_Symbol.js (Snyk). Compare hashes against the lists published by CSA and Aikido.

    Read-only check
    find . -path '*node_modules*' \( -name setup.mjs -o -name Math_Symbol.js -o -name math_init.js \) 2>/dev/null
  3. 03Check for the persistence watcher

    Check the gh-token-monitor paths published by SafeDep, on both macOS and Linux.

    Read-only check
    ls -la ~/.local/bin/gh-token-monitor.sh ~/.config/gh-token-monitor/ ~/Library/LaunchAgents/com.user.gh-token-monitor.plist ~/.config/systemd/user/gh-token-monitor.service 2>/dev/null
  4. 04Check repositories and your GitHub organization

    Look for .claude/ and .vscode/ files you didn't add; search your organization for repositories described as "Shai-Hulud: Here We Go Again", workflows named "Run Copilot", and workflows containing toJSON(secrets) (SafeDep).

    Read-only check
    git log --all --oneline -- .claude/settings.json .vscode/tasks.json
MITIGATEFix / mitigatePatch; block it if you cannot patch yet
  1. 01Pin known-good versions and reinstall without scripts

    Use overrides to pin the versions before the malicious ones (e.g. keyv 5.6.0, flat-cache 6.1.23), purge the bad versions from private registries and caches, then reinstall with npm ci --ignore-scripts (Snyk).

  2. 02Check IDE config files before opening a repository

    Even after clean versions went back to latest, the source repository itself could stay poisoned (Chainguard). Check .claude/settings.json and .vscode/tasks.json before opening, and keep VS Code workspace trust on.

RESPONDRespondIf you find signs of compromise
  1. 01Isolate and remove the dead-man's switch, then rotate credentials

    GitHub's advisory says to rotate all secrets immediately from a different computer; Socket, Snyk and Chainguard warn to isolate the machine and remove gh-token-monitor first, because revoking a token can trigger the handler. Our recommendation is to combine them: cut the infected machine off the network and disable the persistence, then revoke GitHub, npm, cloud and other credentials from a clean computer.

  2. 02Rebuild systems and audit logs

    Rebuild affected machines and CI runners, and audit cloud and source-control logs (Wiz, CSA). Check whether any package you publish got unexpected new versions.

HARDENHardenPrevent the next one
  1. 01Don't run dependency install scripts by default

    npm v12 (generally available since 2026-07-08) no longer runs dependency preinstall, install or postinstall scripts unless approved with npm approve-scripts.

  2. 02Retire bypass-2FA tokens and move to staged publishing

    Bypass-2FA Granular Access Tokens lost sensitive account operations on 2026-07-31, and their direct publishing is due to be removed around January 2027. Note: these releases came out of the project's own CI with valid provenance, and trusted publishing and provenance cannot stop a source repository that is already controlled; staged publishing with human 2FA approval targets that gap more directly (our inference).

  3. 03Egress filtering, hook-file review, dependency allowlists

    Block unexpected Bun downloads and Ethereum RPC traffic; review IDE and AI-agent hook files in pull requests; use dependency allowlists (SafeDep, Chainguard, Wiz).

Full remediation steps and notes
  1. Check whether you are affected. Run npm ls <package> --all and search package-lock, yarn.lock and pnpm-lock for the versions above. Look in node_modules for a preinstall that runs setup.mjs, and for setup.mjs or Math_Symbol.js files. Check for .claude/ and .vscode/ files you didn’t add. For file hashes and domains, compare directly against the lists published by CSA, Aikido and Datadog.
  2. Check for persistence. ~/.local/bin/gh-token-monitor.sh, ~/.config/gh-token-monitor/, ~/Library/LaunchAgents/com.user.gh-token-monitor.plist, ~/.config/systemd/user/gh-token-monitor.service.
  3. If you were hit: the order is disputed. GitHub’s advisory says to treat the machine as fully compromised and rotate all secrets immediately from a different computer. Socket, Snyk and Chainguard warn to isolate the machine and remove gh-token-monitor first, because revoking a token can trigger the handler. Based on these sources, our recommendation is to combine the two: cut the infected machine off the network and disable the persistence, then revoke and rotate GitHub, npm, cloud and all other credentials from a clean computer. Then rebuild, and audit cloud and source-control logs (Wiz, CSA).
  4. Clean up and reinstall. Purge the bad versions from private registries and caches, pin safe versions with overrides, and reinstall with npm ci --ignore-scripts (Snyk).
  5. Check config files before opening a repository. Chainguard warns that even after clean versions returned to latest, the source repository itself could stay poisoned.
  6. Search your GitHub organization for repositories described as “Shai-Hulud: Here We Go Again”, workflows named “Run Copilot”, and workflows containing toJSON(secrets).
  7. Long-term hardening.
    • npm v12 (generally available since 2026-07-08) does not run dependency install scripts unless you approve them with npm approve-scripts.
    • Bypass-2FA tokens lost sensitive account operations on 2026-07-31, and their direct publishing is due to be removed around January 2027. Move to trusted publishing or staged publishing.
    • Caveat: trusted publishing and provenance cannot stop this kind of incident, because the attacker controlled the source and the project’s own CI produced valid attestations for the bad releases. Staged publishing with human 2FA approval targets that gap more directly (our inference, not a claim any source makes about this incident).
    • Filter outbound traffic (block unexpected Bun downloads and Ethereum RPC traffic), review IDE hook files in pull requests, and use dependency allowlists.

Attack flow

Read left to right: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Click an icon for details.

Read top to bottom: this is the order the attack happens in. A blue shield means the step can be stopped; the earlier, the better. Tap an icon for details.

keyv, cacheable and other npm caching packages hijacked: install-time credential theft that spread itself to hundreds of packages (Shai-Hulud / ChainDrop): 1. The attacker takes control of the maintainer's GitHub account → 2. The project's own release pipeline publishes the malicious versions to npm → 3. The victim runs npm install and a preinstall script starts on its own → 4. Credentials are stolen and sent out → 5. The worm spreads to other packages and repositories → 6. A "dead-man's switch" is installed for persistencekeyv, cacheable and other npm caching packages hijacked: install-time credential theft that spread itself to hundreds of packages(Shai-Hulud / ChainDrop)AttackerYour systemExternalThe attacker takes control of the maintainer's GitHub account — How the account was taken over has not been made public. The attacker pushed malicious files straight to the main branch. 1The attacker takescontrol of themaintainer'sGitHub accountThe project's own release pipeline publishes the malicious versions to npm — Publishing went through the project's GitHub Actions, so the releases carried valid provenance (OSV); Snyk says npm's metadata names GitHub Actions as the trusted publisher for keyv@6.0.0. Provenance shows where and how a package was built, not that the source is trustworthy. 2The project's ownrelease pipelinepublishes themalicious version…The victim runs npm install and a preinstall script starts on its own — A loader, setup.mjs, downloads a standalone Bun runtime and runs an obfuscated second stage of about 728 KB. Using Bun is likely meant to dodge monitoring that only watches Node.js. 3The victim runsnpm install and apreinstall scriptstarts on its ownCredentials are stolen and sent out — Targets include cloud, GitHub, npm, Kubernetes, Vault and private keys (OSV); researchers also list SSH, database, Terraform state and AI tool configs. Data is encrypted and sent to attacker servers; the fallback is creating public GitHub repositories described as "Shai-Hulud: Here We Go Again". 4Credentials arestolen and sent outThe worm spreads to other packages and repositories — Stolen npm tokens are used to inject the loader into every package they can publish and republish them. It also commits .claude/settings.json and .vscode/tasks.json into writable repositories, so the loader runs when a developer or AI coding agent opens a clone (OSV; Snyk says the project config has to be trusted and activated), with no npm install needed. 5The worm spreadsto other packagesand repositoriesA "dead-man's switch" is installed for persistence — gh-token-monitor stays resident as a macOS LaunchAgent or Linux systemd user service and checks GitHub every 60 seconds; if the token is revoked it runs an attacker-supplied handler (SafeDep). Wiz says the dead-man's switch is armed selectively based on the attacker server's response. 6A "dead-man'sswitch" isinstalled forpersistenceAttack pathCan be stopped herePlainCVE · plaincve.date/en/vulns/mal-2026-11524-keyv-cacheable-npm-compromise · CC BY 4.0
keyv, cacheable and other npm caching packages hijacked: install-time credential theft that spread itself to hundreds of packages (Shai-Hulud / ChainDrop): 1. The attacker takes control of the maintainer's GitHub account → 2. The project's own release pipeline publishes the malicious versions to npm → 3. The victim runs npm install and a preinstall script starts on its own → 4. Credentials are stolen and sent out → 5. The worm spreads to other packages and repositories → 6. A "dead-man's switch" is installed for persistencekeyv, cacheable and other npm cachingpackages hijacked: install-timecredential theft that spread itself tohundreds of packages (Shai-Hulud …The attacker takes control of the maintainer's GitHub account — How the account was taken over has not been made public. The attacker pushed malicious files straight to the main branch. 1AttackerThe attacker takescontrol of themaintainer's GitHubaccountThe project's own release pipeline publishes the malicious versions to npm — Publishing went through the project's GitHub Actions, so the releases carried valid provenance (OSV); Snyk says npm's metadata names GitHub Actions as the trusted publisher for keyv@6.0.0. Provenance shows where and how a package was built, not that the source is trustworthy. 2Your systemThe project's ownrelease pipelinepublishes the maliciousversions to npmThe victim runs npm install and a preinstall script starts on its own — A loader, setup.mjs, downloads a standalone Bun runtime and runs an obfuscated second stage of about 728 KB. Using Bun is likely meant to dodge monitoring that only watches Node.js. 3Your systemThe victim runs npminstall and a preinstallscript starts on its ownCredentials are stolen and sent out — Targets include cloud, GitHub, npm, Kubernetes, Vault and private keys (OSV); researchers also list SSH, database, Terraform state and AI tool configs. Data is encrypted and sent to attacker servers; the fallback is creating public GitHub repositories described as "Shai-Hulud: Here We Go Again". 4AttackerCredentials are stolenand sent outThe worm spreads to other packages and repositories — Stolen npm tokens are used to inject the loader into every package they can publish and republish them. It also commits .claude/settings.json and .vscode/tasks.json into writable repositories, so the loader runs when a developer or AI coding agent opens a clone (OSV; Snyk says the project config has to be trusted and activated), with no npm install needed. 5ExternalThe worm spreads toother packages andrepositoriesA "dead-man's switch" is installed for persistence — gh-token-monitor stays resident as a macOS LaunchAgent or Linux systemd user service and checks GitHub every 60 seconds; if the token is revoked it runs an attacker-supplied handler (SafeDep). Wiz says the dead-man's switch is armed selectively based on the attacker server's response. 6AttackerA "dead-man's switch" isinstalled for persistenceAttack pathCan be stopped herePlainCVE · CC BY 4.0plaincve.date/en/vulns/mal-2026-11524-keyv-cacheable-npm-compromise
Free to use in reporting and teaching under CC BY 4.0. Attribution is already on the image.
  1. Attacker

    The attacker takes control of the maintainer's GitHub account

    How the account was taken over has not been made public. The attacker pushed malicious files straight to the main branch.

    Defense: Maintainers use phishing-resistant 2FA; require someone else's review before anything lands on main.

  2. Your system

    The project's own release pipeline publishes the malicious versions to npm

    Publishing went through the project's GitHub Actions, so the releases carried valid provenance (OSV); Snyk says npm's metadata names GitHub Actions as the trusted publisher for keyv@6.0.0. Provenance shows where and how a package was built, not that the source is trustworthy.

    Defense: Staged publishing that needs a human 2FA approval before release (our inference, not a claim any source makes about this incident).

  3. Your system

    The victim runs npm install and a preinstall script starts on its own

    A loader, setup.mjs, downloads a standalone Bun runtime and runs an obfuscated second stage of about 728 KB. Using Bun is likely meant to dodge monitoring that only watches Node.js.

    Defense: Install with npm ci --ignore-scripts; move to npm v12 and approve only needed scripts with npm approve-scripts; filter outbound traffic in CI.

  4. Attacker

    Credentials are stolen and sent out

    Targets include cloud, GitHub, npm, Kubernetes, Vault and private keys (OSV); researchers also list SSH, database, Terraform state and AI tool configs. Data is encrypted and sent to attacker servers; the fallback is creating public GitHub repositories described as "Shai-Hulud: Here We Go Again".

    Defense: Use short-lived, least-privilege credentials in build environments; block unexpected outbound connections.

  5. External

    The worm spreads to other packages and repositories

    Stolen npm tokens are used to inject the loader into every package they can publish and republish them. It also commits .claude/settings.json and .vscode/tasks.json into writable repositories, so the loader runs when a developer or AI coding agent opens a clone (OSV; Snyk says the project config has to be trusted and activated), with no npm install needed.

    Defense: Review IDE and AI-agent hook files in pull requests; check these files before opening an unfamiliar repository.

  6. Attacker

    A "dead-man's switch" is installed for persistence

    gh-token-monitor stays resident as a macOS LaunchAgent or Linux systemd user service and checks GitHub every 60 seconds; if the token is revoked it runs an attacker-supplied handler (SafeDep). Wiz says the dead-man's switch is armed selectively based on the attacker server's response.

    Defense: Isolate the machine and remove gh-token-monitor before revoking tokens (Socket, Snyk, Chainguard).

Who is affected

This is not a coding bug. The packages themselves were replaced with malicious versions. So there is no CVE, no NVD CVSS score, and no CISA KEV entry (Snyk’s own vulnerability database does score keyv 6.0.0 at CVSS 4.0 9.3). The official identifiers are OSV MAL- IDs and GitHub security advisories (GHSA), with weakness type CWE-506 (Embedded Malicious Code). GitHub’s “patched versions” field says “None”: the fix is not a patch, it is to stop using those versions.

The 11 directly compromised releases (Snyk, Aikido and Datadog agree):

PackageMalicious versionLast known-good (Snyk)Official advisory
keyv6.0.05.6.0MAL-2026-11524 / GHSA-3p9h-f68w-m6fx
flat-cache6.1.246.1.23MAL-2026-11971 / GHSA-8jxr-wprf-45g8
file-entry-cache11.1.611.1.5MAL-2026-11970 / GHSA-qp89-2g43-jg8j
cacheable2.5.12.5.0MAL-2026-11963 / GHSA-jpjx-r3gh-v5pf
cacheable-request13.0.2013.0.19MAL-2026-11964 / GHSA-mxgw-gq2g-4fq9
cache-manager7.2.107.2.9MAL-2026-11523 / GHSA-p7m5-96hg-gppj
@cacheable/net2.1.12.1.0MAL-2026-11559 / GHSA-pvp8-4g69-xxqh
@cacheable/node-cache3.1.23.1.1MAL-2026-11560 / GHSA-7pv9-q9wh-jqc3
@cacheable/memory2.2.12.2.0MAL-2026-11558 / GHSA-583f-9h76-9fx2
@cacheable/utils2.5.12.5.0MAL-2026-11561 / GHSA-8v3r-r9vg-5r66
ecto5.0.15.0.0MAL-2026-11966 / GHSA-g3q3-j6vf-388h

The npm registry’s publish times also show ecto 5.0.0 (2026-06-25) as the release before 5.0.1. Endor Labs gives a general rule: pin to versions published before 2026-08-04 09:30 UTC.

@keyv/ adapter packages: sources disagree.* OSV and GHSA also list version 6.0.0 of 19 @keyv/* packages as malicious (for example @keyv/redis is MAL-2026-12020 and @keyv/compress-gzip is MAL-2026-12010): @keyv/bigmap, @keyv/cloudflare-kv, @keyv/compress-brotli, @keyv/compress-gzip, @keyv/compress-lz4, @keyv/dynamo, @keyv/encrypt-node, @keyv/encrypt-web, @keyv/etcd, @keyv/memcache, @keyv/mongo, @keyv/mysql, @keyv/postgres, @keyv/redis, @keyv/serialize-msgpackr, @keyv/serialize-superjson, @keyv/sqlite, @keyv/test-suite, @keyv/valkey. The npm registry shows these 6.0.0 releases were published on 2026-08-04 between 09:30 and 09:32 UTC, a few minutes before keyv@6.0.0. Socket includes them in its timeline but says these versions do not contain the preinstall hook; it treats them as suspect because of the account compromise and confirms the payload only in the packages in the table above. The Amazon Inspector analysis attached to the OSV records (for example @keyv/redis) likewise reports no install-time execution or credential theft. Chainguard says the @keyv/* adapter packages were never affected. This page cannot tell which side is right; our suggestion is to be conservative and not use the 6.0.0 release of these packages.

These packages are downloaded enormously. Per Aikido, keyv sees about 604 million downloads a month, flat-cache about 580 million, file-entry-cache about 571 million, cacheable-request about 137 million and cacheable about 30 million.

Second wave: the worm. The malware used stolen npm tokens to infect other packages. Counts differ because each researcher took a snapshot at a different time:

SourcePackagesVersions
OSV400+—
Aikidoat least 4441,381
SafeDep444 (12 organizations)2,234
Endor Labs3841,136
CSA Singapore—over 1,300

Named downstream scopes include @ornikar/*, @onereach/*, @or-sdk/*, @servicetitan/*, @qlik/*, @picsart/* and @deliveroo/*. Overall: more than 400 packages and well over 1,000 versions.

Who was likely to pick it up (our inference, not stated by any source): the bad keyv release is a new major version, 6.0.0, so projects allowing only ^5.x would not get it automatically. But the bad flat-cache, file-entry-cache, cacheable-request and cache-manager releases are patch bumps, so projects using ^ or ~ ranges that re-resolved dependencies while the bad versions were available could have received them automatically. The bad versions were published on 2026-08-04, but infected downstream packages kept being published until 13:18 that day (SafeDep), and private registries, mirrors or caches can keep versions npm has removed, so later installs could still pick them up; that is why Snyk advises purging them from private registries and caches.

This assumes install scripts ran. The malware starts from a preinstall script, and OSV says to treat any environment that installed the version “with install scripts enabled” as fully compromised. Installing with --ignore-scripts, or with npm v12 (generally available since 2026-07-08, which does not run dependency preinstall, install or postinstall scripts unless explicitly allowed), does not trigger it. We have not checked the defaults of other package managers. The IDE config-file path below does not need an install at all.

Also, you can be hit without running npm install: opening a repository with planted .claude/ or .vscode/ config files can trigger execution, but sources describe the condition differently. OSV says the loader runs when a developer or AI coding agent opens a clone. Snyk says this execution path appears when a developer or coding agent trusts and activates project-local configuration, and that VS Code may ask first, depending on workspace trust and user settings.

How it works

1. Way in: the maintainer’s account. The attacker controlled the maintainer’s GitHub account. How is unknown. The attacker pushed malicious files straight to main, then reset and replayed the git history to hide what happened.

2. The project’s own pipeline signed off on it. OSV says the attackers pushed the payload to the source repository and cut releases through GitHub Actions, so the poisoned versions reached npm with a valid, signed provenance attestation. Snyk says npm’s metadata names GitHub Actions as the trusted publisher for keyv@6.0.0. Snyk’s key point: provenance proves where and how a package was built, not that its source is trustworthy.

3. Runs at install time. The attacker added a preinstall script to package.json, so the loader setup.mjs runs during npm install, before any application code. It downloads a standalone Bun runtime (1.3.13) and then runs a roughly 728 KB obfuscated second stage, Math_Symbol.js (also called math_init.js). Socket and Datadog think Bun was chosen to slip past monitoring that only watches Node.js.

4. What it steals. Cloud credentials (AWS, GCP, Azure, including instance metadata), GitHub and npm tokens, Kubernetes service-account tokens, HashiCorp Vault, SSH keys, database connection strings (SafeDep says it looks for MongoDB, MySQL, PostgreSQL and Redis URLs with inline credentials), Terraform state, Docker configs, and Stripe and Slack tokens. Wiz adds crypto wallets and AI tool credentials and configs (Claude, OpenAI, Cursor, Gemini). Datadog says that on Linux with sudo available it reads the memory of GitHub Actions runners. Workflows named “Run Copilot” dump every repository secret at once.

5. Where it goes. Data is encrypted and sent to attacker servers, whose list is looked up from an Ethereum smart contract. The fallback is creating public GitHub repositories described as “Shai-Hulud: Here We Go Again” (SafeDep counted more than 1,000). Datadog notes the server’s reply is executed as code, which amounts to a general-purpose backdoor.

6. How it spreads. Two routes: it uses stolen npm tokens to inject the loader into every package they can publish and republishes them (SafeDep saw some organizations publishing about one package per second), and it commits .claude/settings.json (a Claude Code SessionStart hook) and .vscode/tasks.json (runOn: folderOpen) into repositories it can write to.

7. Dead-man’s switch. It installs gh-token-monitor (a macOS LaunchAgent or Linux systemd user service), which checks GitHub every 60 seconds and runs an attacker-supplied handler if the token is revoked (SafeDep, Snyk). Wiz says the switch in this version is armed selectively based on the attacker server’s response: the server can reply with a command that arms it and names the token to watch.

Risky install pattern (conceptual illustration, not malicious code):

Show code example(bash)
# In CI: resolve loose version ranges on the fly and let every dependency's install scripts run
npm install

Safer install pattern (conceptual illustration):

Show code example(bash)
# Install exact versions from the lockfile and run no dependency lifecycle scripts
npm ci --ignore-scripts
Show code example(json)
{
  "overrides": {
    "keyv": "5.6.0",
    "flat-cache": "6.1.23",
    "file-entry-cache": "11.1.5",
    "cacheable-request": "13.0.19",
    "cache-manager": "7.2.9"
  }
}

(Adjust override versions to the major versions your dependency tree actually uses.)

Timeline

Time (2026-08-04 UTC unless noted)Event
09:02First malicious commit adds payload files and the preinstall hook (Datadog)
09:04VS Code and Claude Code hooks added (SafeDep)
09:12–09:18Repository history reset and replayed to hide traces (Datadog)
09:30–09:326.0.0 releases of 19 @keyv/* packages published, later listed as malicious by OSV and GHSA (npm registry; Socket says these versions lack the preinstall hook)
09:35keyv@6.0.0 published with provenance
09:38First package outside the two namespaces infected (Socket)
10:06–10:07Malicious commit pushed to the cacheable repository and a GitHub release created (Datadog)
10:09–10:28Malicious cacheable-family (10:09–10:14) and ecto (10:28) releases published to npm (Datadog, Snyk; Socket lists the cacheable family at 10:09–10:14)
10:18–10:20First public warnings (Snyk)
10:39–11:11npm removes flat-cache@6.1.24, cacheable-request@13.0.20 and cache-manager@7.2.10; at 11:16 eight malicious releases were still tagged latest (Snyk)
13:18Last known poisoned publish (SafeDep)
Same dayOSV and GHSA records published
About 20:40npm reportedly declares the incident contained and rotates write-scoped bypass-2FA tokens as a precaution (second-hand only, unconfirmed)
2026-08-06CSA Singapore publishes AD-2026-009

There is no CVE publication date and no CISA KEV addition.

Further reading

  • Scoring: there is no CVE, so no NVD score. GitHub rates the keyv advisory Critical (malware), and Snyk’s vulnerability database scores keyv 6.0.0 at CVSS 4.0 9.3 (Critical).
  • Version notes: when Chainguard wrote, it marked the versions of file-entry-cache, cacheable, @cacheable/memory and @cacheable/node-cache as uncertain.
  • Not established: how the maintainer account was compromised; the current state of these versions on npm (we could not check); any statement from the maintainer (none found; the only related issue on the keyv repository, #2051, was opened by a third party and is closed).
  • Campaign: Datadog and CSA call this malware “ChainDrop”, from the Shai-Hulud family. Wiz calls it a descendant of “Mini Shai-Hulud”, built on public repositories from TeamPCP, but does not say TeamPCP carried out this attack. SafeDep says a direct link to earlier incidents is unconfirmed; the “Here We Go Again” marker only suggests continuity or shared infrastructure.
  • Background: the original Shai-Hulud was found on 2025-09-14; GitHub removed more than 500 packages and announced npm hardening. The 2026-05-11 Mini Shai-Hulud / TanStack incident was attributed by Wiz with high confidence to TeamPCP, and got in through a chain of GitHub Actions weaknesses, unlike this account takeover. Chainguard counts keyv as the third 2026 wave using the same toolkit (April: PyTorch Lightning; May: @antv) but does not list TanStack, so the wave numbering depends on the source. For the April and @antv waves this page has only Chainguard as a source.
  • Related weakness type: CWE-506.

Verification Checked item by item against sources by AI under our review rules, all passed; not human-reviewed and not yet reproduced in our lab

AI review2026-09-30 · review rules

Verification records describe the environment and the result only, never reproduction steps or code that could attack other people’s systems. See our policy.

Sources

  1. AdvisoryMAL-2026-11524: Malicious code in keyv (npm) · OSV, 2026-08-04 · accessed 2026-09-23
  2. AdvisoryMAL-2026-11963: Malicious code in cacheable (npm) · OSV, 2026-08-04 · accessed 2026-09-23
  3. AdvisoryMAL-2026-11971: Malicious code in flat-cache (npm) · OSV, 2026-08-04 · accessed 2026-09-23
  4. AdvisoryMalware in keyv (GHSA-3p9h-f68w-m6fx) · GitHub Advisory Database, 2026-08-04 · accessed 2026-09-23
  5. AdvisoryMalware in cacheable (GHSA-jpjx-r3gh-v5pf) · GitHub Advisory Database, 2026-08-04 · accessed 2026-09-23
  6. AdvisoryMalware in flat-cache (GHSA-8jxr-wprf-45g8) · GitHub Advisory Database, 2026-08-04 · accessed 2026-09-23
  7. AdvisoryMAL-2026-11970: Malicious code in file-entry-cache (npm) · OSV, 2026-08-04 · accessed 2026-09-24
  8. AdvisoryMalware in file-entry-cache (GHSA-qp89-2g43-jg8j) · GitHub Advisory Database, 2026-08-04 · accessed 2026-09-24
  9. AdvisoryEmbedded Malicious Code in keyv (SNYK-JS-KEYV-18515941) · Snyk Vulnerability Database, 2026-08-04 · accessed 2026-09-24
  10. AdvisoryOngoing npm Supply Chain Attack Affecting Keyv and Related Packages ("Shai-Hulud" Worm) · Cyber Security Agency of Singapore, 2026-08-06 · accessed 2026-09-23
  11. Other[URGENT] Repository and package compromised (issue #2051) · keyv project (GitHub), 2026-08-04 · accessed 2026-09-23
  12. ResearchPopular npm packages in the keyv and cacheable namespaces compromised in active supply chain attack · Socket, 2026-08-04 · accessed 2026-09-23
  13. ResearchKeyv and friends compromised in npm supply chain attack · Aikido Security, 2026-08-04 · accessed 2026-09-23
  14. Researchkeyv and cacheable npm compromise: 400+ packages · SafeDep, 2026-08-04 · accessed 2026-09-23
  15. Researchkeyv and cacheable npm Package Hijacked in Supply Chain Attack · Wiz, 2026-08-04 · accessed 2026-09-23
  16. ResearchInside the keyv npm Supply Chain Compromise · Snyk, 2026-08-04 · accessed 2026-09-23
  17. ResearchThe keyv and cacheable npm Supply Chain Attack: Inside the Mini Shai-Hulud Campaign · Chainguard, 2026-08-04 · accessed 2026-09-23
  18. Research'ChainDrop' worm compromises hundreds of popular npm packages · Datadog Security Labs, 2026-08-04 · accessed 2026-09-23
  19. ResearchNPM Malware Compromises keyv and cacheable with 500M+ Weekly Downloads and Spreads to Hundreds of Packages · Endor Labs, 2026-08-04 · accessed 2026-09-23
  20. OtherLegitimate provenance did not stop the malware · cuon (note.com) · accessed 2026-09-23
  21. Vendornpm install-time security and GAT bypass2fa deprecation · GitHub Changelog, 2026-07-08 · accessed 2026-09-28
  22. VendorRestricting npm bypass-2FA granular access tokens · GitHub Changelog, 2026-07-31 · accessed 2026-09-23
  23. VendorOur plan for a more secure npm supply chain · GitHub Blog, 2025-09-22 · accessed 2026-09-23
  24. ResearchMini Shai-Hulud Strikes Again: TanStack + more npm Packages Compromised · Wiz, 2026-05-11 · accessed 2026-09-23
  25. AdvisoryMAL-2026-11964: Malicious code in cacheable-request (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  26. AdvisoryMAL-2026-11523: Malicious code in cache-manager (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  27. AdvisoryMAL-2026-11559: Malicious code in @cacheable/net (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  28. AdvisoryMAL-2026-11560: Malicious code in @cacheable/node-cache (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  29. AdvisoryMAL-2026-11558: Malicious code in @cacheable/memory (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  30. AdvisoryMAL-2026-11561: Malicious code in @cacheable/utils (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  31. AdvisoryMAL-2026-11966: Malicious code in ecto (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  32. AdvisoryMAL-2026-12020: Malicious code in @keyv/redis (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  33. AdvisoryMAL-2026-12010: Malicious code in @keyv/compress-gzip (npm) · OSV, 2026-08-04 · accessed 2026-09-28
  34. Other@keyv/redis package metadata (npm registry) · npm registry · accessed 2026-09-28
  35. Otherecto package metadata (npm registry) · npm registry · accessed 2026-09-28

Press brief

In one sentence

On August 4, 2026, malicious versions of npm caching packages such as keyv, flat-cache and cacheable were published (per Aikido, keyv and flat-cache are each downloaded about 600 million times a month, cacheable about 30 million). The attacker controlled the maintainer's GitHub account and let the project's own release pipeline push the malware to npm, so the versions carried normal-looking provenance. The malware stole developer and CI credentials at install time and spread itself to more than 400 packages and over a thousand versions. The incident is part of the Shai-Hulud series, has no CVE, and is tracked under OSV IDs such as MAL-2026-11524.

Key facts

Main identifier
OSV MAL-2026-11524 (keyv 6.0.0), alias GHSA-3p9h-f68w-m6fx; no CVE osv.dev
Weakness type
CWE-506 Embedded Malicious Code; no patched version github.com
Spread
At least 444 packages and 1,381 versions (Aikido; counts vary by source) aikido.dev
First malicious keyv release
2026-08-04 09:35 UTC securitylabs.datadoghq.com
Singapore CSA advisory
AD-2026-009, 2026-08-06 csa.gov.sg

Confirmed

  • keyv 6.0.0, flat-cache 6.1.24, file-entry-cache 11.1.6 and cacheable 2.5.1 are listed as malicious by OSV and GitHub advisories (CWE-506).
  • The malicious versions were published through the project's own GitHub Actions, with valid provenance (OSV).
  • The malware steals credentials at install time, uses stolen npm tokens to infect other packages, and plants auto-run settings for Claude Code and VS Code.

Unconfirmed / disputed

  • Whether npm trusted publishing was used: Snyk says npm's metadata names GitHub Actions as the trusted publisher for keyv@6.0.0, while OSV only says the releases went out through GitHub Actions with valid provenance; 6.0.0 has been removed from npm, so we could not check it ourselves.
  • How the maintainer account was compromised has not been disclosed.
  • Dates differ: Snyk's vulnerability database gives 2026-08-03 as the disclosed and introduced date for keyv, while the npm registry shows keyv@6.0.0 published at 2026-08-04 09:35 UTC and Socket and Datadog also say August 4; we use the npm registry date, and the reason for Snyk's difference is unknown.
  • Whether the 6.0.0 releases of the @keyv/* adapter packages are malicious: OSV and GHSA list them as malicious, Socket says they lack the preinstall hook and treats them only as suspect, and Chainguard says @keyv/* was never affected.
  • Total infected packages and versions: researchers report from 384 to 444 packages and 1,136 to 2,234 versions.
  • Who ran the attack: Wiz says the malware is heavily based on code TeamPCP published openly, so the tooling is related, but does not say TeamPCP carried out this attack; the operator is unconfirmed (SafeDep also calls a link to earlier incidents unconfirmed). npm's statement that the incident was contained is only available to us second-hand.

Quotable line

These packages had a perfectly valid birth certificate. The problem was that the birthplace itself had been taken over.

Images

Download the share image (PNG) · Attack flow diagram (downloadable)

Please credit "PlainCVE" and link to this page. Full citation format is under "How to cite" below. Found a factual error? Report it.

How to cite this page

This article is CC BY 4.0. Please keep the attribution and link when republishing.

PlainCVE Team (2026). "keyv, cacheable and other npm caching packages hijacked: install-time credential theft that spread itself to hundreds of packages (Shai-Hulud / ChainDrop)". PlainCVE. https://plaincve.date/en/vulns/mal-2026-11524-keyv-cacheable-npm-compromise (accessed YYYY-MM-DD)
BibTeX
@misc{mal202611524keyvcacheablenpmcompromise2026,
  title  = {keyv, cacheable and other npm caching packages hijacked: install-time credential theft that spread itself to hundreds of packages (Shai-Hulud / ChainDrop)},
  author = {PlainCVE Team},
  year   = {2026},
  howpublished = {PlainCVE},
  url    = {https://plaincve.date/en/vulns/mal-2026-11524-keyv-cacheable-npm-compromise},
  note   = {Updated 2026-09-30}
}