The signature was valid and the package was poisoned
If somebody builds or maintains software for you, whether that is an in-house developer, an agency, or a contractor, you have probably been told at some point that the modern answer to supply-chain risk is signing. Packages get cryptographically signed by the build system. You verify the signature. If it checks out, the code came from the place it claims to have come from.
That advice is sound, and it is worth following. Last week it also failed, in a way that is worth understanding before you rely on it again.
What happened
On 4 August, attackers took over the GitHub account of the maintainer behind keyv, a small storage library that npm serves roughly 127 million times a week. npm is the package registry that nearly all JavaScript and Node.js software installs its building blocks from, and a single business application typically pulls in hundreds of these packages without anybody choosing them individually.
The attackers pushed malicious files straight to the main branch and immediately cut a release. That spread into the maintainer's other packages, then outward. Aikido, the security firm that published the first detailed write-up, counted at least 444 packages across 1,381 versions with a combined two billion monthly installs. Microsoft Threat Intelligence put it at more than 400 packages across unrelated publishers and named the worm ChainDrop.
The payload runs automatically during installation, before any of your tests or scanners get a look at it. It hunts for credentials on the machine: npm tokens, GitHub tokens, cloud keys, Kubernetes and HashiCorp Vault secrets, database credentials, private keys. On build servers it reads the runner's memory directly to pull out stored secrets. Then it uses whatever publishing access it found to poison more packages, which is what makes it a worm rather than a one-off.
The part that matters
The poisoned keyv release carried valid provenance. Not forged, not bypassed: correct.
Provenance here means a cryptographic record of how a package was built, tying the published file back to a specific build run. It is the mechanism behind "verified" badges in package registries, and it is the control that supply-chain guidance has been pushing hard for several years, under names like SLSA and OIDC signing.
It worked exactly as designed. Because the attackers pushed their code into the real repository, the release went through the project's genuine GitHub Actions workflow. The build system signed what it was handed. As the reporting on the campaign put it, the attestation correctly identified the build process but could not establish that the source entering it was safe.
The same pattern shows up in the commit that planted the malicious files: it carried a green "verified" badge and was attributed to github-actions[bot]. The signature was valid. That tells you the credential used was genuine. It tells you nothing about who was holding it.
This is the useful lesson, and it generalises well beyond npm. Signing proves a chain of custody. It does not inspect the goods. A signed package tells you it came through the expected door, which is genuinely worth knowing, and says nothing whatsoever about whether the contents are safe. If your mental model was "signed means checked", it needs adjusting, because attackers have now demonstrated the gap at scale.
What to do
Find out whether you were exposed, using lockfiles rather than a list. The affected package tags changed repeatedly during the incident, and the published totals count poisoned artefacts, not infected machines. That means a namespace blocklist will both miss things and flag clean releases. The reliable question is which exact versions were resolved on a given machine or build server between 4 and 5 August, which is what a lockfile records.
Treat an affected install as credential exposure, not a malware clean-up. Anything that ran the payload should have its reachable credentials rotated from a known-clean machine. One operational detail is worth passing on: the malware watches for token revocation and can act on it, so responders are advised to remove that watcher before rotating, not after.
Turn off automatic install scripts. The payload ran through an npm "preinstall" hook, code the package asks to run during installation. npm version 12 blocks unapproved lifecycle scripts by default; older clients do not. Ask whoever maintains your build pipeline which they are on.
Ask the ownership question rather than the tooling one. The account takeover, not the signing, was the failure. Worth asking of anyone who can publish software in your name: who can push to the main branch, what protects those accounts, and would a release cut at three in the morning by a compromised account look any different from a normal one?
Signing is still worth doing. It just answers a narrower question than the marketing around it suggests, and knowing which question it answers is the difference between a control and a comfort blanket.
How Steelwise can help
Working out what your software actually pulls in, who can change it, and what would happen if one of those accounts were taken over is a short, defined piece of work. Get in touch if you would like a second opinion on yours.
Further reading
- NCSC guidance on supply chain security
- SLSA, the supply-chain framework behind build provenance
- npm documentation on package provenance
- OWASP guidance on dependency management