Strobesstrobes
Platform
Solutions
Resources
Customers
Company
Pricing
Book a Demo
Strobesstrobes

Strobes connects every exposure signal to autonomous action, so security teams fix what matters, prove what works, and stop chasing noise.

Book a DemoTalk to an expert
ISO 27001SOC 2CREST
  • Platform
  • Platform Overview
  • Agentic Exposure Management
  • AI Agents
  • Integrations
  • API & Developers
  • Workflows & Automation
  • Analytics & Reporting
  • Solutions
  • Exposure Assessment (EAP)
  • Attack Surface Management
  • Application Security Posture
  • Risk-Based Vulnerability Management
  • Adversarial Exposure Validation (AEV)
  • AI Pentesting
  • Pentesting as a Service
  • CTEM Framework
  • By Industry
  • Financial Institutions
  • Technology
  • Retail
  • Healthcare
  • Manufacturing
  • By Roles
  • CISOs
  • Security Directors
  • Cloud Security Leaders
  • App Sec Leaders
  • Resources
  • Quick Agentic Pentest
  • Blog
  • Customer Stories
  • eBooks
  • Whitepapers
  • Datasheets
  • Videos & Demos
  • Exposure Management Academy
  • Pentesting ROI Calculator
  • Pentest Health Check
  • Security Tool ROI Calculator
  • Company
  • About Strobes
  • Meet the Team
  • Trust & Security
  • Contact Us
  • Careers
  • Become a Partner
  • Technology Partner
  • Partner Deal Registration
  • Press Release

Weekly insight for security leaders

CTEM research, agentic AI trends, and what's actually moving the needle.

© 2026 Strobes Security Inc. All rights reserved.

Privacy PolicyTerms of ServiceCookie PolicyAccessibilitySitemap
Back to Blog
Keyv and Cacheable npm supply chain attack: compromised package versions in a dependency chain
Supply Chain SecurityCybersecurityApplication Security

Keyv and Cacheable Supply Chain Attack Explained

Shubham JhaAugust 4, 202614 min read

Table of Contents

  • Table of Contents
  • What happened in the keyv and cacheable compromise?
  • Which packages and versions are affected?
    • The headline package is the one semver blocks
  • Why is the blast radius bigger than the package list suggests?
  • How does the payload actually work?
  • What credentials does it steal?
  • Why didn’t npm provenance stop this?
  • What should you do in the next hour?
  • Indicators of compromise
  • How do you stop the next one?
  • FAQ
    • Am I affected if I never installed keyv directly?
    • Does a lockfile protect me?
    • The package had valid npm provenance. Doesn’t that mean it’s safe?
    • Is it enough to delete node_modules and reinstall?
    • Should I revoke my GitHub token immediately?
    • Is this the same as Shai-Hulud 2.0 from November 2025?
    • How many packages are affected in total?
  • Sources
  • Related Reading

Authors

S
Shubham Jha

Share

Table of Contents

  • Table of Contents
  • What happened in the keyv and cacheable compromise?
  • Which packages and versions are affected?
    • The headline package is the one semver blocks
  • Why is the blast radius bigger than the package list suggests?
  • How does the payload actually work?
  • What credentials does it steal?
  • Why didn’t npm provenance stop this?
  • What should you do in the next hour?
  • Indicators of compromise
  • How do you stop the next one?
  • FAQ
    • Am I affected if I never installed keyv directly?
    • Does a lockfile protect me?
    • The package had valid npm provenance. Doesn’t that mean it’s safe?
    • Is it enough to delete node_modules and reinstall?
    • Should I revoke my GitHub token immediately?
    • Is this the same as Shai-Hulud 2.0 from November 2025?
    • How many packages are affected in total?
  • Sources
  • Related Reading

Authors

S
Shubham Jha

Share

Published August 4, 2026, within hours of first disclosure. This is an active incident, and the numbers below are a snapshot, not a final count.

TL;DR
  • ✓On August 4, 2026 at roughly 09:00 UTC, an attacker who controlled the GitHub account behind keyv and cacheable pushed a credential stealer directly to main and cut releases across the whole package family.
  • ✓The poisoned tarballs carry valid npm provenance signed by GitHub Actions. Every cryptographic check passes. This is the second npm compromise in three months to ship malware with legitimate attestations.
  • ✓The payload is a descendant of Mini Shai-Hulud. It adds a preinstall hook that downloads the Bun runtime and runs a 728 KB obfuscated stealer targeting .npmrc tokens, GitHub CLI tokens, AWS credentials, Vault tokens, Kubernetes configs, and crypto wallets.
  • ✓The worm has already jumped namespaces. Public tracking put the count at 868 packages across 1,381 versions by 13:37 CEST, with over 2 billion combined monthly installs.
  • ✓The version everyone is naming is the one semver blocks. No range in the tree accepts keyv@6.0.0. The releases that install silently are cacheable-request@13.0.20, cache-manager@7.2.10, and @cacheable/utils@2.5.1, all patch bumps inside live caret ranges.

Table of Contents

  • What happened in the keyv and cacheable compromise?
  • Which packages and versions are affected?
  • Why is the blast radius bigger than the package list suggests?
  • How does the payload actually work?
  • What credentials does it steal?
  • Why didn't npm provenance stop this?
  • What should you do in the next hour?
  • Indicators of compromise
  • How do you stop the next one?
  • FAQ

What happened in the keyv and cacheable compromise?

An attacker took over the GitHub account of the maintainer who owns keyv, cacheable, flat-cache, and file-entry-cache, then used that access to publish malicious versions across the entire family. Wiz Research puts the start of visible activity at around 09:00 UTC, when the attacker first planted IDE persistence payloads in the keyv repository, and then published a new keyv release carrying the stealer.

The publishing method matters more than the initial access. Rather than stealing an npm token and pushing tarballs from a laptop, the attacker pushed malicious files straight to the main branch and triggered a normal release. The release workflow did what it always does. It built the packages, requested an OIDC token, and published to npm with signed provenance.

So the tarballs on the registry right now are cryptographically genuine. They really were built by that repository, in that workflow, on that commit. The attestation is correct. The code is malware.

Wiz attributes the payload to the “Mini” Shai-Hulud family, with similarities to the TeamPCP and @antv campaigns from earlier this year. No confirmed attribution yet, and given how much of the Shai-Hulud toolchain is now public, copycat activity is likely.

Which packages and versions are affected?

These are the versions with published numbers as of this writing. Treat any release from this family published on August 4, 2026 as suspect until you have verified the tarball contents yourself.

PackageMalicious versionInstall volume
keyv6.0.0~127M weekly
cacheable-request13.0.20~133M monthly
cache-manager7.2.10~16M monthly
@cacheable/utils2.5.1~34M monthly
flat-cachesee note~565M monthly
file-entry-cachesee note~557M monthly
cacheablesee note~29M monthly
@cacheable/memorysee note~28M monthly
@cacheable/node-cachesee note~5.9M monthly

The headline package is the one semver blocks

Every writeup on this incident leads with keyv and its 127 million weekly downloads. We installed the affected chains and checked which malicious versions the declared ranges actually accept. The answer is not the one the headline implies.

$ npm i eslint got cache-manager && npm ls keyv
eslint@10.8.0
└─ file-entry-cache@8.0.0  → flat-cache@4.0.1 → keyv@4.5.4
got@15.1.0
└─ cacheable-request@13.0.19 (got declares ^13.0.18) → keyv@5.6.0
cache-manager@7.2.9
└─ @cacheable/utils@2.5.0 (declares ^2.5.0) → keyv@5.6.0

Now run the ranges against the malicious versions:

Consumer and declared rangeMalicious versionResolves?
got → cacheable-request ^13.0.1813.0.20pulls it
cache-manager top level ^7.2.97.2.10pulls it
cache-manager → @cacheable/utils ^2.5.02.5.1pulls it
flat-cache → keyv ^4.5.46.0.0blocked
got → keyv ^5.6.06.0.0blocked
cacheable-request → keyv ^5.6.06.0.0blocked

keyv@6.0.0 cannot reach you transitively. Nothing in the tree declares ^6, so a caret range on v4 or v5 refuses it. The only people who pulled malicious keyv are those who ran npm i keyv@latest or pinned to 6.

The versions that install silently are cacheable-request@13.0.20, cache-manager@7.2.10, and @cacheable/utils@2.5.1. All three are patch bumps sitting inside live caret ranges. got@15.1.0 declares ^13.0.18, which happily accepts 13.0.20.

Worth noting on the keyv release itself: the keyv README states v5 is in maintenance mode with no new majors planned. A surprise 6.0.0 from a project that publicly stopped shipping majors is an anomaly a human reviewer catches in about four seconds. It’s also, ironically, why that particular release was the least dangerous one in the set.

If you were treating semver ranges as a safety boundary, this is where the assumption breaks. Not because ranges failed, but because they protected you from the package everyone is talking about and did nothing about the three nobody is.

Why is the blast radius bigger than the package list suggests?

Because almost nobody installs these packages on purpose. They’re plumbing.

flat-cache and file-entry-cache are how ESLint caches lint results between runs. If your repository has an .eslintcache file, those two are in your tree. cacheable-request sits under got, which sits under thousands of HTTP clients and SDKs. keyv sits under cacheable-request. cache-manager shows up under NestJS caching setups.

Run this and see for yourself:

npm ls keyv cacheable-request flat-cache file-entry-cache cache-manager

Most teams get a result. Very few of them have ever heard of the maintainer.

That depth is the whole point of the target selection. A compromise at the framework layer gets noticed in minutes because thousands of developers are watching the repo. A compromise four levels down in a lint cache utility gets noticed when a vendor’s telemetry catches it. Nobody is reading changelogs for file-entry-cache.

This is the same structural problem we wrote about after the TanStack npm supply chain attack in May and the axios compromise before it. The difference is depth. TanStack hit packages developers chose. This one hit packages developers inherited.

How does the payload actually work?

Two files land in every compromised package, plus one line in package.json:

"scripts": {
  "preinstall": "node setup.mjs"
}

preinstall runs before installation completes. There’s no opportunity to inspect anything first. If you ran npm install against an affected version, setup.mjs executed.

setup.mjs is a small obfuscated dropper with exactly one job: silently fetch the Bun runtime from github[.]com/oven-sh/bun/releases/download/bun-v1.3.13/ and use it to execute the real payload.

execFileSync(<bun binary>, ['<script_dir>/Math_Symbol.js'], {
  stdio: 'inherit',
  cwd: <script_dir>
})

Downloading Bun is a deliberate evasion choice. The traffic goes to github.com, which every corporate proxy allows and every CI runner already talks to. Endpoint tooling watching for curl to an unknown host sees nothing. And running the payload under Bun rather than Node sidesteps Node-specific hooks and monitoring.

Math_Symbol.js is the actual stealer: 728 KB of obfuscated JavaScript, dropped as node_modules/keyv/Math_Symbol.js.

What credentials does it steal?

Everything a developer machine or CI runner keeps lying around. The payload runs a set of extractors, each aimed at a specific secret store:

  • npm registry auth tokens from .npmrc
  • GitHub CLI tokens, including classic PATs, session tokens, and OIDC tokens
  • AWS access keys and session tokens from ~/.aws/credentials
  • HashiCorp Vault client tokens from VAULT_TOKEN, with an HTTP fallback if the variable isn’t set
  • Kubernetes configs, Terraform credentials, and SSH keys
  • AI tool configuration files
  • Cryptocurrency wallets

Wiz adds that the malware harvests secrets from CI/CD environments, fingerprints build runners, and enumerates cloud environments to widen access from whatever it finds.

Two details are worth calling out because they change how you should respond.

First, stolen tokens get validated before exfiltration. GitHub tokens are checked against the live API to confirm they’re active. This isn’t a spray-and-pray dump, it’s a filtered set of working credentials, which means whoever receives it already knows what still opens doors.

Second, the command and control has changed. Alongside a conventional exfiltration domain (npm-cache[.]com) and the Shai-Hulud pattern of committing stolen secrets to public GitHub repos, this variant uses Ethereum RPC endpoints as part of its C2 channel. Three of them: eth-mainnet.nodereal[.]io, go.getblock[.]io, and eth.llamarpc[.]com.

Blockchain RPC as C2 is a real escalation for defenders. You cannot sinkhole it, you cannot take down the infrastructure, and the traffic looks like any other web3 API call. If your egress policy allows public Ethereum RPC endpoints, and most do by default, this channel works.

The exfiltration repos carry the description Shai-Hulud: Here We Go Again, and initial commits include the string IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients.

That’s a bluff aimed at GitHub’s abuse team, not a technical claim.

Why didn’t npm provenance stop this?

Because provenance answers “where did this build come from” and never claimed to answer “is this code safe.”

An npm provenance attestation binds a tarball to a repository, a commit, and a workflow run, signed via Sigstore. That’s genuinely useful against token theft, where an attacker publishes from a machine that isn’t your CI. It does nothing when the attacker has write access to the repository, because then the malicious commit is the source of truth and the signature over it is accurate.

Here’s the uncomfortable comparison:

Metricaxios (Mar 2026)TanStack (May 2026)keyv / cacheable (Aug 2026)
Initial accessmaintainer accountCI workflow abuse via pull_request_targetmaintainer GitHub account
Publish pathstolen npm tokenOIDC token extracted from runner memorynormal release workflow on main
Valid provenance?noyesyes
Execution stageinstall scriptinstall scriptpreinstall
C2 channelHTTPHTTPHTTP plus Ethereum RPC

Three compromises, three different initial-access techniques, and the trend line on provenance is going the wrong way. A green provenance badge tells you the build was reproducible. It cannot tell you the maintainer’s session cookie wasn’t stolen an hour earlier.

If your software composition analysis gate treats “has valid provenance” as a pass condition, it just passed this.

What should you do in the next hour?

Work in this order. The sequence matters because rotating credentials from an infected machine hands the attacker your new tokens.

1. Find out whether you’re exposed.

npm ls keyv cacheable-request flat-cache file-entry-cache cache-manager cacheable
grep -rn "Math_Symbol" node_modules/ 2>/dev/null
ls -d /tmp/bun-dl-* 2>/dev/null

Also check your CI logs for preinstall output and any outbound requests to the IOC domains below.

2. Assume the machine is compromised, and treat it that way.

If a poisoned version installed, the host had arbitrary code execution as your user. Removing the package does not undo that. Rebuild developer workstations and CI runners rather than cleaning them. This is the step teams skip, and it’s the one that determines whether you’re still compromised next week.

3. Rotate from a clean machine, in dependency order.

npm tokens first, then GitHub PATs and OIDC trust relationships, then AWS keys and instance roles, then Vault tokens, then Kubernetes service account tokens, then SSH keys. Rotating AWS before GitHub is pointless if the attacker still holds a GitHub token that can read your Actions secrets.

One caution on revocation. The Mini Shai-Hulud variant behind the TanStack attack included a destructive daemon that wiped the user’s home directory when it detected token revocation. There’s no confirmation of that behavior in this variant yet, and absence of evidence this early means nothing. Rotate from a separate machine and treat the infected host as evidence, not as a workstation.

4. Hunt for what the attacker did with the credentials.

Review CloudTrail, GitHub audit logs, and npm publish history for the window starting 09:00 UTC on August 4. Look for unfamiliar public repositories under your org, new self-hosted Actions runners, workflow file additions you didn’t author, and package publishes nobody remembers making.

5. Check whether you became a spreader.

If a developer with publish rights was infected, your own packages may already be carrying the payload. That’s how @ornikar/* and @qlik/* ended up on the affected list. Diff your latest published tarballs against your source tree.

Indicators of compromise

Domains

  • npm-cache[.]com (exfiltration, 104.21.35[.]216, Cloudflare)
  • eth-mainnet.nodereal[.]io (Ethereum RPC C2, 35.175.164[.]77)
  • go.getblock[.]io (Ethereum RPC C2, 185.44.207[.]215)
  • eth.llamarpc[.]com (Ethereum RPC C2, 172.67.167[.]200, Cloudflare)

File artifacts

  • /tmp/bun-dl-*/
  • node_modules/keyv/Math_Symbol.js
  • setup.mjs alongside a preinstall hook in any cache-family package

Strings

  • Shai-Hulud: Here We Go Again (exfiltration repo description)
  • IfYouBlockThisAPIKeyItWillCrashTheLiveProductionServersOfAllThirdPartyClients

How do you stop the next one?

There will be a next one. Since September 2025, the interval between major npm compromises has been measured in weeks, and the toolchain is public now. Plan for recurrence, not prevention.

Turn off install scripts. npm config set ignore-scripts true breaks a small number of packages with native builds, and it would have stopped this attack cold. Allowlist the handful of packages that actually need lifecycle scripts.

Use npm ci, never npm install, in CI. npm ci installs exactly what the lockfile pins. npm install resolves ranges, which is how cacheable-request@13.0.20 reached machines whose owners never asked for it.

Add a minimum release age. pnpm 11 ships a one-day cooldown by default and blocks exotic subdependencies. A 24-hour delay would have made this incident a non-event for anyone using it, because detection happened within hours. This is the single highest-leverage control available today and it costs you one day of freshness.

Stop treating provenance as an integrity check. It’s a build-origin attestation. Keep verifying it, but pair it with behavioral analysis of what the package does at install time.

Know your dependency tree before you need to. The teams that answered “are we affected” quickly today had an SBOM they could query. The ones that didn’t spent the morning running npm ls across forty repositories. If you don’t have that inventory, start with an SBOM.

Treat developer machines as production. Every credential this payload stole was sitting in a home directory or an environment variable. The workstation is where cloud access actually lives, and most vulnerability management programs still don’t look there. ASPM closes that gap by connecting what’s in your code to what’s exposed in your cloud, and open source security scanning in the dev workflow catches malicious dependencies before they reach a laptop.

Strobes tracks npm and PyPI supply chain incidents in Strobes VI, with affected package versions, IOCs, and linked advisories per incident.

FAQ

Am I affected if I never installed keyv directly?

Probably yes. keyv, flat-cache, file-entry-cache, and cacheable-request are almost always transitive dependencies. ESLint pulls in the cache packages, and got pulls in cacheable-request. Run npm ls against the package names rather than checking your package.json.

Does a lockfile protect me?

Only if you install from it. npm ci respects the lockfile exactly. npm install can resolve a new patch version inside an existing caret range, which is precisely how cacheable-request@13.0.20 and cache-manager@7.2.10 spread. If your CI runs npm install, the lockfile did not protect you.

The package had valid npm provenance. Doesn’t that mean it’s safe?

No. Provenance proves a tarball was built by a specific repository and workflow. When the attacker controls that repository, the attestation is accurate and the code is still malicious. This is the second confirmed npm attack in three months to ship malware with valid attestations.

Is it enough to delete node_modules and reinstall?

No. preinstall already ran arbitrary code as your user. Clear the package manager cache, then rebuild the host and rotate every credential it could reach. Reinstalling clean packages removes the delivery mechanism, not the compromise.

Should I revoke my GitHub token immediately?

Revoke it, but do it from a different machine. A related Mini Shai-Hulud variant destroyed the user’s home directory when it detected revocation. That behavior isn’t confirmed here, but the infected host is not where you want to find out.

Is this the same as Shai-Hulud 2.0 from November 2025?

Related, not identical. Wiz assesses this payload as a descendant of the “Mini” Shai-Hulud family, with overlap against the TeamPCP and @antv campaigns. The Ethereum RPC C2 channel is new to this variant.

How many packages are affected in total?

The count is moving. Public tracking showed 868 packages across 1,381 versions as of 13:37 CEST on August 4, representing over 2 billion combined monthly installs. That includes worm propagation into unrelated namespaces, and it will be higher by the time you read this.

Sources

  1. Mini Shai-Hulud: Compromised @antv npm packages enable CI/CD credential theft, Microsoft Security
  2. Postmortem: TanStack npm supply-chain compromise
  3. OSV malicious packages database

Related Reading

  • The TanStack npm Supply Chain Attack That Hit 170 Packages
  • axios npm Supply Chain Attack: Compromised Package Delivers RAT
  • npm Package Compromised in Phishing Attack
  • What Is an SBOM (Software Bill of Materials)?
  • Supply Chain Incident Response and Exposure Assessment with Strobes AI
Tags
keyv npm supply chain attackcacheable npm compromisedMini Shai-Huludnpm provenance bypasskeyv 6.0.0 malwarecacheable-request 13.0.20npm preinstall malwaresoftware supply chain security

Stop chasing vulnerabilities Start reducing exposure

See how Strobes AI agents validate and fix your most critical exposures automatically.

Book a Demo
Continue Reading

Related Posts

Top databreaches june 2026
Data BreachesSupply Chain Security

Top 8 Data Breaches and Exposures of June 2026

The 8 confirmed data breaches of June 2026, from a 24-billion-record credential dump to ShinyHunters' PeopleSoft and Klue OAuth campaigns. What happened and how to defend.

Jun 30, 202613 min
Vulnerability Validation
Exposure ValidationApplication Security

Vulnerability Validation: Why Most of Your Scanner Backlog Is Noise

Vulnerability validation proves which scanner findings are real, reachable, and exploitable. Why manual triage fails and how agentic validation scales.

Jun 9, 202619 min
How to pentest single-page applications - React, Angular and Vue SPA security testing guide
Penetration TestingApplication Security

How to Pentest Single-Page Applications (React, Angular, Vue)

Learn how to pentest React, Angular, and Vue SPAs. Covers DOM XSS, client-side routing bypass, JS bundle secrets, and why traditional DAST scanners fail.

Jun 4, 202623 min