DevOps & Infra 3 min min read 2 views

The npm worm: when installing a dependency becomes a security incident

E
Eduardo Piasson
11 Aug 2026
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:

  1. That the registry delivers what the maintainer intended to deliver. A compromised account breaks that.
  2. That installing a package is a read operation. It is not — lifecycle scripts execute arbitrary code on your machine and in your CI.
  3. 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-scripts cuts 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, never npm 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?"

Newsletter

New articles straight to your inbox.

✓ Check your email to confirm your subscription.

Related posts