Résumé

Shai-Hulud, in September 2025, was the moment the npm ecosystem's worst fear came true: a worm that spreads by itself. It began with a wave of compromised packages, the most prominent being @ctrl/tinycolor (over two million weekly downloads), and from there it did something no npm attack had done before. When its malware ran on a developer's machine, it hunted for every credential it could find, then used the developer's own npm token to republish itself into all of their other packages automatically, with no attacker involvement, jumping from maintainer to maintainer like an infection. More than 500 packages were compromised, including some from CrowdStrike. It is the first true npm worm, and the template for the even more aggressive Shai-Hulud 2.0 that followed weeks later.

How it happened

Named for the sandworm in Dune, Shai-Hulud began on 14 September 2025 with a first burst of compromised packages (the earliest observed was rxnt-authentication; the highest-profile was @ctrl/tinycolor) and then ran a self-sustaining loop. It was itself downstream of the August 2025 s1ngularity attack on the Nx build system, which had harvested the maintainer credentials that seeded it. When the malware executed in a developer's environment, it harvested that developer's credentials, npm tokens, GitHub personal access tokens, and AWS, GCP, and Azure secrets, using the TruffleHog secret scanner to find them. It exfiltrated those secrets to attacker webhooks and to public GitHub repositories, and established persistence by planting a malicious GitHub Actions workflow (shai-hulud-workflow.yml).

The part that made it historic was self-replication. Using the stolen npm token, the malware authenticated to npm and automatically republished trojanized versions of every package the victim maintained, spreading exponentially with no operator involvement at all. Each compromised maintainer became a new launch point, so the worm grew on its own. That is what makes it a worm rather than an ordinary one-shot supply-chain attack, and more than 500 packages (about 526) were ultimately caught up in it.

The damage

More than 500 packages were compromised, including 17 from the security vendor CrowdStrike, and a large volume of developer and cloud credentials was harvested at ecosystem scale. The deeper damage was structural: an npm attack that propagates on its own means the list of affected packages grows exponentially rather than staying fixed, which is a fundamentally harder problem to contain. CISA issued a federal alert, and the incident forced npm and GitHub to overhaul publishing: they revoked all legacy "classic" npm tokens in December 2025, replaced long-lived tokens with short-lived session tokens, and pushed OIDC-based trusted publishing as the recommended path.

Why Shai-Hulud still matters

It is the first self-replicating npm worm, a genuine watershed. Before it, npm supply-chain attacks were one-shot: poison a package and wait. Shai-Hulud weaponised stolen publish tokens to spread itself, turning every compromised maintainer into a spreader. The defences target that mechanism directly: use short-lived, narrowly scoped publish tokens or OIDC trusted publishing so a stolen token cannot be reused to self-propagate; require phishing-resistant 2FA on maintainer accounts; run installs and CI in isolated, least-privilege environments with no standing cloud credentials; disable install scripts where feasible; and scan for and rotate leaked secrets fast. It returned, nastier and at greater scale, as Shai-Hulud 2.0 two months later.

Comment le corriger

  • Treat every machine that ran an infected package as fully compromised: rotate npm, GitHub, and cloud credentials immediately, and revoke the worm's published versions.
  • Search GitHub for the worm's exfiltration repositories and webhooks to find which secrets leaked, and check your own packages for unauthorized republished versions.
  • Remove the malicious GitHub Actions workflow it added for persistence, and rebuild from a clean lockfile pinned to known-good versions.

Comment l’éviter

  • Use short-lived, narrowly scoped publish tokens or OIDC trusted publishing, so a stolen token cannot be reused to self-propagate, the worm's core mechanism.
  • Require phishing-resistant 2FA on maintainer and publisher accounts.
  • Run installs and CI in isolated, least-privilege environments with no standing cloud credentials, and disable install scripts where feasible.
  • Scan continuously for leaked secrets and rotate fast, and pin dependencies so a freshly poisoned version cannot flow straight into your builds.

Références

Vulnérabilités liées

Tout Supply chain →