· 7 min read

A Hacked GitHub Account Turned keyv Into a Worm That Hit 440+ npm Packages. It Specifically Targets Your Claude Code and VS Code Config.

At 09:35 UTC on August 4, someone with access to the GitHub account behind keyv — a caching library with roughly 127 million weekly npm downloads — pushed a malicious release. Within about 30 minutes, the same maintainer's other packages went down with it: cacheable, flat-cache, file-entry-cache, and a handful more, all swept into a self-propagating worm. If you run npm install on almost anything, one of these was probably in your tree without you ever typing its name.

What actually happened

The attacker compromised the maintainer's GitHub account and pushed keyv@6.0.0 plus roughly ten related malicious releases directly to main, then cut new versions immediately. Because the releases came through GitHub Actions with valid provenance, npm had no reason to flag them. Each poisoned package got two new files, setup.mjs and Math_Symbol.js, and a preinstall hook wired to run setup.mjs automatically the moment anyone installed the package. That script downloads the Bun runtime and runs a roughly 728KB obfuscated payload that harvests GitHub tokens, npm tokens, AWS credentials, Vault tokens, Kubernetes configs, and crypto wallet files. Any stolen publish access got reused immediately to poison more packages, which is why security researchers gave this the "Mini Shai-Hulud" name — a worm, not a one-off leak.

The scale estimates vary by who's counting and when they counted. SafeDep verified 353 poisoned versions across 79 package names. Aikido's broader scan put the footprint at 868 packages across 1,381 versions. Whichever number you trust, the combined download volume across the affected package family runs into the billions per month. This wasn't a niche dependency. It was infrastructure.

The part built for you specifically

Most supply-chain worms stop at stealing tokens. This one didn't. The payload also drops .claude/settings.json and .vscode/tasks.json into the compromised repository, wired to auto-run the next time the workspace is trusted inside Claude Code or VS Code. Trust a workspace, and the hook fires again on your machine, independent of whether you ever re-ran npm install.

That's the detail that separates this from a generic credential-stealing story. Whoever built this worm knew that a meaningful share of the developers touching these packages run an AI coding agent with filesystem access, and built a second persistence path specifically for that. A caching library three dependency levels deep in your project is not something most solo developers have ever opened, let alone audited. That's exactly the layer this attack was designed to hide in.

Why "I don't use keyv directly" doesn't clear you

You don't need to depend on keyv directly to be exposed. It's a transitive dependency of a long list of popular packages — logging libraries, HTTP clients, caching layers inside larger frameworks. If anything in your package-lock.json or pnpm-lock.yaml pulled in keyv, cacheable, flat-cache, or file-entry-cache at a compromised version between August 4 and whenever your project maintainer patched it, the preinstall script ran on your machine whether you noticed or not.

I run a lot of side projects with dependency trees I haven't personally inspected in months. That's the normal state of things for a solo operator — you can't manually review every transitive dependency of every project, and pretending otherwise isn't a realistic policy. What is realistic is running the check below once, today, instead of trusting that "I didn't do anything unusual" means you're fine.

The ten-minute check

Run this in every active project:

npm ls keyv cacheable flat-cache file-entry-cache 2>/dev/null

If any of those resolve to a version installed on or after August 4, treat the machine as potentially compromised, not just the project. From there:

  1. Diff .claude/settings.json and .vscode/tasks.json in every repo against their last known-good git history. Anything unexpected wasn't there before this week.
  2. Rotate any credential that lived on that machine and touched npm, GitHub, AWS, or Vault since August 4 — tokens, not just passwords, since the payload specifically targeted token files like .npmrc.
  3. Check your global npm cache and ~/.bun for anything that shouldn't be there; the payload pulls the Bun runtime down even on machines that don't normally use it.
  4. If you publish packages yourself, confirm your own publish access hasn't been used for anything you didn't do — the worm's whole mechanism is stealing publish rights to spread further.

None of this requires a security team. It requires ten minutes and the willingness to assume you might be affected instead of assuming you're not.

What I'd actually do

Run the npm ls check across every repo you have locally right now, not just the one you're actively working in. Old side projects sitting untouched on your machine are exactly the ones nobody re-audits, and a preinstall hook doesn't care whether the project is "active." If you find a hit, rotate credentials first and investigate second — the cost of an unnecessary token rotation is a few minutes; the cost of a live stolen AWS key is a bill you don't want to see.

The honest counter-take: supply-chain worms like this get patched fast once discovered, and by the time you're reading this, the compromised versions are almost certainly already pulled from the registry. Running the check is still worth it, because the window between "compromised version published" and "you happened to install it" already closed for a lot of people before the story made headlines. Being current on the patched version doesn't undo an install that already ran the payload three days ago.

Author

Sources

Stay in the Loop

Get new posts delivered to your inbox. No spam, unsubscribe anytime.

Newsletter coming soon. Set PUBLIC_CONVERTKIT_FORM_ID in .env to activate.

Related Posts