Most supply chain attacks need a person to make a mistake. This one needed a person to make a mistake once, and then it ran by itself.
What happened
On 4 August 2026, attackers obtained the credentials of the maintainer behind keyv and cacheable — small, unglamorous npm packages that sit underneath a great deal of JavaScript. The keyv family alone accounts for well over a billion monthly downloads.
What they published was not simply a backdoored release. It was a worm.
The malicious package carried a preinstall hook — a legitimate npm feature that runs commands before a package is installed. That hook dropped a Bun runtime and executed an obfuscated payload which swept the machine for credentials: npm and GitHub tokens, AWS, GCP, Azure and Alibaba Cloud keys, Kubernetes service accounts, SSH keys, Vault tokens, and API keys for AI services. Researchers counted over 300 credential patterns in the harvester. The haul was compressed, encrypted and shipped out.
Then came the part that made it a worm. Where it found an npm token with publish rights that did not require two-factor authentication, it enumerated every package that account could write to and infected each one. Those packages were installed by other developers, on other machines, with other tokens.
Within roughly four hours, the campaign had published over 2,200 malicious versions across more than 400 unique packages. Organisations named in the fallout include Deliveroo, Picsart, Qlik and ServiceTitan. The malware is a descendant of the Shai-Hulud family; attribution beyond that remains unconfirmed, and we would leave it there.
Three things this exploits that are not bugs
npm install executes code. Install hooks exist for legitimate reasons — compiling native modules, setting up a package after download. But the consequence is that adding a dependency runs arbitrary code on the machine doing the installing, before anyone has reviewed a line of it. Every npm install is an act of trust, and most are performed without thinking of it that way.
Your build server is the richest target you own. Developers think about their laptops. Attackers think about CI. A build agent holds deployment credentials, cloud keys, registry tokens and signing material, all in environment variables, all reachable by any process the build starts. A laptop gets one person's access; a build server gets the organisation's.
Publishing tokens without MFA turn one compromise into many. The worm's propagation depended entirely on finding tokens that could publish without a second factor. Where maintainers had enforced 2FA on publish, the chain stopped.
This is not only a developer problem
It is tempting to file this under "something for the engineering team". That is a mistake for two reasons.
First, almost every organisation now ships software of some kind, even if it is only a website, an internal tool or a few automation scripts. If anything in your business runs npm install, pip install or composer install in an automated pipeline, you have this exposure.
Second, the credentials this worm went looking for are not development credentials. They are production cloud keys, Kubernetes access and secrets-manager tokens. A compromise that begins in a build pipeline ends in the infrastructure that runs the business. The blast radius is set by what the build server can reach, not by what the developer was working on.
What to actually do
Pin your dependencies and commit the lockfile. A lockfile means a build installs the exact versions you tested, not whatever was newest at 09:00 UTC on the day of an attack. The organisations hurt worst by fast-moving campaigns are the ones resolving versions fresh on every build.
Disable install scripts where you can. npm ci --ignore-scripts prevents the preinstall hook that carried this payload. Some packages genuinely need their scripts; allowlist those few deliberately rather than permitting all of them by default.
Treat the build server as production. Short-lived credentials rather than long-lived keys, scoped to exactly what the pipeline needs. No shared cloud administrator keys in CI variables. Separate runners for trusted and untrusted work.
Require MFA on publish for anything you ship. If your organisation maintains public or internal packages, this is the control that breaks the propagation chain.
Know what you depend on. A software bill of materials sounds bureaucratic until an advisory names 400 packages and you need an answer within the hour about whether any of them are yours. The question "are we affected?" should take minutes, not days.
Rotate on suspicion, not on confirmation. If a compromised package reached a machine holding credentials, assume those credentials left. Rotation is cheap; an investigation that proves a negative is not.
The summary
ChainDrop did not break npm. It used npm as designed — install hooks, publish tokens, transitive dependencies — and the design assumes maintainers' accounts are not compromised. One account was, and the rest was arithmetic.
The defensive position is not to stop using open source, which is neither possible nor sensible. It is to accept that your dependency tree is attack surface you did not write, to keep the credentials near it short-lived and narrow, and to be able to answer quickly when the advisory lands.
Sources
- Shai-Hulud strikes again: CHAINDROP worm hits 400+ npm packages — Elastic Security Labs
- 'ChainDrop' worm compromises hundreds of popular npm packages — Datadog Security Labs
- ChainDrop npm worm: Bun-loaded CI/CD credential harvester — StepSecurity
- ChainDrop: the Mini Shai Hulud npm worm's latest wave hits keyv and cacheable — Expel



