The Worm That Publishes Itself

Most supply-chain compromises need someone steering. An attacker phishes a maintainer, publishes a bad version, and waits. The window closes when somebody notices, and the blast radius is whatever that one account could reach.

Shai-Hulud removed the steering.

The loop#

The mechanism is small enough to describe in a sentence. Once the malware is running during an install and finds a valid npm token in the environment, it queries the registry for every package that token can publish, injects a preinstall hook into each one, bumps the patch version, and publishes.

Each of those packages then runs the same code on somebody else’s machine. If that machine also holds a publishing token – a CI runner, a maintainer’s laptop mid-release – the loop closes and runs again.

There is no command-and-control server to seize and no operator to arrest. The credentials it collects are the same credentials it needs to keep going, which is what makes it a worm rather than a campaign.

Scale#

The first wave, in September 2025, compromised over 1,300 package versions carrying a combined two billion monthly downloads, reaching widely used caching libraries including keyv, cacheable, flat-cache and file-entry-cache.

A second wave in November 2025 was faster. Within hours of first detection it had compromised more than 700 packages, created over 27,000 malicious GitHub repositories, and exposed roughly 14,000 secrets across 487 organisations.

It has not stopped. A variant tracked as Mini Shai-Hulud surfaced in May 2026 and reached 170-odd npm packages plus two on PyPI across 404 malicious versions.

Why the numbers read strangely#

Two billion monthly downloads is not two billion machines. It is mostly CI. The same lockfile resolves the same afternoon on every pull request in every repository that depends on it, and each of those is a download.

That inflates the headline and understates the risk at the same time. A CI runner is a worse place to be compromised than a laptop: it holds deployment credentials, it runs unattended, and its network egress is rarely watched as closely as an engineer’s would be.

What actually contains it#

Not detection. Detection is what tells you it already happened – the response to both waves was fast and still measured in hours, and the worm’s whole design is to spend those hours reproducing.

What contains it is the install step refusing to run untrusted code: lifecycle scripts off by default, a cooldown before a fresh version is eligible to install at all, and publishing credentials that cannot be replayed from a stolen token. Those are the subject of a separate piece.

Those controls do not require a perfect malware detector. They make the common path slower and narrower: a bad release has less opportunity to execute, less time to spread, and fewer credentials from which to start another release.

Sources#