Sari la conținut
Developer Tools

Shai-Hulud: npm Gets Its First Self-Spreading Worm

One phished maintainer token was enough to poison hundreds of packages with no attacker at the keyboard.

·4 min de citit ·vev.dev

In September 2025 the npm registry, the place almost every JavaScript project downloads its building blocks from, was hit by malware that did something new. Palo Alto Networks' Unit 42 investigated it and described a novel, self-replicating worm. It is known as Shai-Hulud, after the public GitHub repository the malware creates to hold what it steals. The distinction from an ordinary compromise matters: nobody had to sit at a keyboard and poison each package. The malware published the next batch itself.

The way in was unremarkable. Maintainers were sent messages dressed up as official npm correspondence, telling them their multi-factor authentication options needed updating. Anyone who filled in the form on the other end handed over the account access that publishing to the registry depends on. Everything after that was automatic.

The poisoned packages carried a post-installation script — a small program npm runs on your machine the moment a package is installed. It went looking for credentials on whatever computer it landed on: the .npmrc file where npm tokens are kept, personal access tokens for GitHub, keys for cloud services from Amazon, Google and Microsoft. The search itself was outsourced to TruffleHog, a legitimate secret-scanning tool that security teams run against their own code, turned around and pointed at the victim. Where a working npm token turned up, the developer's own account became the delivery mechanism: the worm rewrote the packages published under that account and pushed fresh versions out. Those versions reached everyone who installed them, and the loop began again.

Why a worm is a different kind of problem

The usual supply-chain incident has a shape teams know how to handle. One package is compromised, a version number is named, you check whether you use it and you move on. Shai-Hulud broke that shape, because the population of poisoned packages grew on its own — every maintainer it caught became the launch point for the next wave. Unit 42 describes the reach as hundreds of packages, among them @ctrl/tinycolor, a small colour utility the firm notes takes millions of downloads a week. As this is written the picture is still being assembled.

The second half is worse than the packaging problem. The stolen secrets were not quietly hoarded. The malware committed what it found to a public GitHub repository named Shai-Hulud, and also sent data to a webhook.site endpoint. Anyone who ran an install of a poisoned package should assume those credentials were readable by strangers, not merely held by one attacker.

So the honest summary is this. A dependency your project has used safely for three years can turn hostile between one Tuesday and the next, without the maintainer doing anything wrong beyond clicking a convincing email. And any machine that ran an install during the window — a laptop, but far more dangerously a build server, which usually holds the keys to everything — has to be treated as having leaked.

What this means if you are building something

Install from a lockfile, not from a range. The lockfile records the exact versions that were tested. Commit it, and have your build install from it rather than resolving fresh versions on every run. This alone means a package poisoned this morning does not arrive in this afternoon's deployment.

Switch off install scripts in the build. npm can be told to ignore post-install scripts, either per command or in the project's .npmrc. That is precisely the mechanism this worm used. A few packages that compile native code genuinely need scripts, so test before making it the rule — but a build server running arbitrary code from the internet on every deploy is the default that made this possible.

Give tokens the smallest job and a short life. A publishing token does not belong in a pipeline that only reads packages. Scope tokens narrowly, rotate them on a schedule rather than after an incident, and enforce multi-factor authentication on npm and GitHub accounts — Unit 42's own advice runs to rotating developer credentials, auditing dependencies and making MFA mandatory.

Write the response down before you need it. When a dependency is compromised mid-project the questions are always the same: which builds ran in the window, which tokens were on those machines, who rotates them, in what order, and who tells the client. Deciding that at 11pm is how things get missed.

Our reading: none of this is exotic security work, and all of it is cheaper than the alternative. If your project has a package.json and nobody can say today which of these four things are true of it, that is the finding.

Sources

Distribuie
Contactează-ne

Ai o idee de proiect? Solicită o ofertă!

Ai un proiect? Scrie-ne dacă vrei să lucrăm împreună la ceva interesant. Sau ai nevoie de ajutorul nostru? Nu ezita să ne contactezi.