ChainDrop: The npm Attack That Shipped With Valid Provenance
ChainDrop compromised hundreds of npm packages with valid provenance and stole cloud and CI credentials. What happened, why signing fell short, what to do.
On August 4, 2026, one of the broadest npm supply chain attacks of the year began. Known as ChainDrop, it’s a Shai-Hulud variant, and it didn’t exploit a single code vulnerability: it took over a maintainer’s GitHub account and published malicious versions of packages that countless projects depend on without knowing it.
What makes it especially uncomfortable for teams that had “done their homework” is that those versions carried valid provenance. They passed the very check many people considered sufficient.
This article explains what happened, why provenance wasn’t enough, and what your team should do, whether or not you were affected.
What happened
The attacker took over the GitHub account of the keyv maintainer, pushed directly to the main branch and cut releases. Because publishing ran through GitHub Actions, the malicious versions shipped with provenance signed by that same workflow.
It spread fast. According to Aikido’s August 5 update, at least 444 packages (across 1381 versions) were compromised, with more than 2 billion monthly installs combined.
On August 6, the Cyber Security Agency of Singapore (CSA) published advisory AD-2026-009 listing the identified malicious versions. Among them:
| Package | Malicious version |
|---|---|
| keyv | 6.0.0 |
| flat-cache | 6.1.24 |
| file-entry-cache | 11.1.6 |
| cacheable-request | 13.0.20 |
| cacheable | 2.5.1 |
| cache-manager | 7.2.10 |
This table isn’t the full list; check the sources at the end of the article for details.
The detail every JavaScript team should notice: flat-cache and file-entry-cache are dependencies of common tooling like ESLint. You didn’t need to use keyv directly to be exposed; having a linter in your project or pipeline was enough.
What the malicious code did
The payload ran through a preinstall hook, meaning it executed during dependency installation, before anyone imported the package. It was after credentials:
- npm and GitHub tokens, including OIDC tokens.
- AWS, Azure and GCP credentials.
- Kubernetes and Vault credentials.
- API keys for AI tools.
Think about where npm install runs: on developer laptops with cloud access, and on CI/CD runners with permission to deploy to production. That’s exactly the prize.
Why valid provenance wasn’t enough
Provenance answers one specific question: was this package built from this repository and this CI workflow? It’s a useful defense against packages published from an attacker’s machine with a stolen token.
But it doesn’t answer another question: is the code in that repository legitimate? If someone controls the maintainer’s account, they can push to main and let the official pipeline sign the result. The signature is authentic; the content isn’t.
The lesson isn’t to abandon provenance, but to stop treating it as a synonym for trust. It’s one layer, and it needs to be paired with controls over what runs at install time, which secrets are within reach, and how publishing accounts are protected.
Immediate response: a checklist if you may have been exposed
The CSA’s recommendations are straightforward: remove affected versions from development and CI/CD environments, rotate all credentials, and treat affected hosts as compromised. In practical terms:
- Search every lockfile across your repositories for the versions listed in the advisories.
- Identify which laptops and runners ran an install with those versions, and since when.
- Remove the affected versions, pin known-good versions and regenerate the lockfile.
- Clear the npm cache, CI caches and any container images built with those dependencies.
- Treat affected machines and runners as compromised: isolate and rebuild them instead of “cleaning” them.
- Rotate every credential that was within reach: npm, GitHub, AWS, Azure, GCP, Kubernetes, Vault and AI API keys.
- Review GitHub, cloud and npm audit logs for unusual activity since August 4.
If you’re unsure whether a machine was exposed, assume it was. Rotating one credential too many costs far less than leaving a compromised one active.
Prevention: what changes with npm 12
A month before the attack, on July 8, 2026, npm 12 became generally available with changes aimed squarely at this kind of threat:
- Lifecycle scripts blocked by default. Dependency
preinstall,installandpostinstallscripts, as well as implicit node-gyp builds, no longer run unless explicitly allowed. - Explicit approval. Scripts are approved with
npm approve-scripts, and the allowlist is stored inpackage.json, which makes it visible in code review. - Git and remote URL dependencies. They require
--allow-gitand--allow-remote, respectively. - Granular tokens with 2FA bypass. Since early August 2026 they can no longer perform sensitive account and package management, and around January 2027 they lose the ability to publish directly.
A payload that depends on a preinstall hook won’t run under npm 12 unless that package has approved scripts. That doesn’t remove the malicious package from your dependency tree, but it closes the door this attack used.
Prevention checklist for development teams
| Control | Why it matters |
|---|---|
| Upgrade to npm 12 on laptops and CI | Blocks dependency install scripts by default |
| Review every change to the approved scripts list | The allowlist in package.json is code: it goes through a pull request |
Use npm ci with a committed lockfile |
Reproducible installs, no surprise new versions |
| Don’t adopt freshly published versions immediately | Gives time for compromises to be detected |
| Least privilege in CI | The install step shouldn’t see deployment secrets |
| Ephemeral runners | A compromised runner doesn’t survive the next job |
| Branch protection and strong 2FA on publishing accounts | Makes a direct push to main harder |
| Stop publishing with 2FA-bypass tokens | npm is phasing them out |
| Treat AI API keys as production secrets | They were targeted too |
FAQ
We don’t use keyv. Are we safe?
Not necessarily. flat-cache and file-entry-cache are dependencies of common tooling like ESLint. Check the full lockfile, not just your direct dependencies.
Would npm 12 have protected us?
It would have prevented a dependency’s preinstall hook from running without explicit approval, which was this payload’s mechanism. You still need to remove the affected versions and apply the other controls.
Is updating the packages enough?
No. If a malicious version was ever installed, the credentials on that machine should be considered stolen. Updating without rotating credentials leaves the attacker’s access intact.
Conclusion
ChainDrop showed that a valid signature only proves where a package came from, not that it’s safe. Real defense is layered: control what runs at install time, reduce the secrets within reach and protect the accounts that publish. If your team wants outside help reviewing its pipeline or prioritizing these changes, feel free to reach out.
Sources
Have a project in mind?
Let's talk about how we can help you achieve your technology goals.
Schedule a free consultation