The npm worm: when installing a dependency becomes a security incident
What happened last week
On August 4, 2026, attackers compromised the GitHub account of the maintainer behind keyv, a key-value storage library with roughly 127 million weekly npm downloads. From that access they published malicious versions that spread across more than 400 packages from unrelated publishers — including flat-cache and cache-manager, according to Microsoft Threat Intelligence.
The payload is a variant of the worm known as Shai-Hulud: a heavily obfuscated, self-propagating credential stealer that runs through the preinstall lifecycle hook — that is, before package installation even finishes. It harvests secrets from the environment and uses those secrets to publish new malicious versions of other packages, closing the loop on its own.
It was not an isolated case. In March 2026, a compromised maintainer account turned axios into a malware delivery vehicle for about three hours: any clean install in that window pulled a cross-platform RAT straight into the build. In June, at least 32 packages under the @redhat-cloud-services namespace were compromised.
And the backdrop is worse than any single incident: Sonatype's 2026 report counted more than 454,000 new malicious open-source packages published in 2025, pushing the cumulative blocked total past 1.2 million — a 75% jump in a year.
Why traditional defenses miss this
These attacks do not depend on a flaw in your code. They exploit three assumptions almost every pipeline accepts without question:
- That the registry delivers what the maintainer intended to deliver. A compromised account breaks that.
- That installing a package is a read operation. It is not — lifecycle scripts execute arbitrary code on your machine and in your CI.
- That CI is a disposable environment. It is usually the place holding the company's most valuable secrets: deploy tokens, cloud keys, registry credentials.
Vulnerability scanners do not help here. There is no CVE for "this version, published forty minutes ago, contains a worm."
What you can do this week
In order of cost/benefit:
- Disable lifecycle scripts by default in CI.
npm ci --ignore-scriptscuts off the most used execution vector. Some packages need native builds — handle those exceptions explicitly instead of allowing everything. - Always install from the lockfile.
npm ci, nevernpm install, in any automated environment. Without a respected lockfile, a^range pulls the compromised version on the first build after publication. - Adopt a quarantine window for new versions. Most malicious packages are unpublished within hours. Delaying adoption of versions younger than a few days removes almost the entire exposure window at near-zero cost.
- Get long-lived secrets out of CI. Replace static tokens with ephemeral credentials via OIDC. If a worm runs in your pipeline, it walks away with a token that expires in minutes, not the master key.
- Separate the install job from the job that holds secrets. Installing dependencies and deploying do not need to happen in the same environment with the same permissions.
- Enforce 2FA and scoped publishing keys on your own packages. This attack started at a maintainer account — yours is one too.
The point that usually gets missed
The instinctive reaction after an incident like this is to cut dependencies. Good intention, low return: the problem is rarely how many packages you have, it is how many of them can execute code in your most privileged environment.
A project with 800 dependencies installed with no scripts, from a lockfile, on a runner with no secrets, is in far better shape than a project with 80 dependencies installed via npm install on a runner holding the production key.
The right question is not "how many dependencies do I have?" It is "what exactly happens when I run install, and with which permissions?"
Related posts
CI/CD for small teams: a pipeline that fits in one afternoon
CI/CD does not need a dedicated platform team. It needs a minimal pipeline, honest about w...
How to tell AI-generated content from the real thing
AI-generated text, images, voice, and video already fool attentive people. You cannot trus...