An independent re-analysis by Goldberg Security Research of a publicly-reported campaign, drawn from open reporting (CISA, Unit 42, Wiz, Microsoft — see references). Not original discovery.
Why it mattered
Shai-Hulud was the first successful self-propagating worm in the npm ecosystem. Earlier supply-chain incidents were one-shot package compromises; Shai-Hulud automated the spread, turning each victim maintainer into a launch point for the next — the closest the JavaScript ecosystem has come to a true worm.
Initial compromise
The entry point was a credential-phishing campaign spoofing npm and prompting maintainers to "update" their MFA settings — harvesting their npm authentication token in the process.
Self-replication
This is the core of the threat, and it is elegant in the worst way:
- Using a stolen token, the payload authenticates to the npm registry as the compromised maintainer.
- It enumerates that maintainer's other packages.
- It injects its malicious code into each, bumps the version, and re-publishes them.
- Every developer who installs an infected package becomes a new spreader — exponential growth, no operator intervention.
Payload
The malicious postinstall script runs on install and harvests secrets aggressively:
- Runs TruffleHog (a legitimate secret scanner, repurposed) to find credentials on the host.
- Harvests environment variables and cloud keys exposed via the instance metadata service (IMDS).
- Exfiltrates findings to attacker-created public GitHub repositories named "Shai-Hulud" — a distinctive, public IOC.
Scale & variants
The first wave hit 500+ packages including the widely-used @ctrl/tinycolor. The
November 2025 Shai-Hulud 2.0 backdoored ~796 unique packages totalling over 20
million weekly downloads, and a 2026 "Mini Shai-Hulud" resurgence extended into PyPI. The recurrence
underlines that npm token hygiene and lifecycle-script trust remain systemic weak points.
Detection & prevention
- Hunt for public GitHub repos named
Shai-Huludunder your org's developers; review npm publish logs for unexpected version bumps. - Install with
--ignore-scriptsin CI; gate lifecycle scripts. - Use short-lived, scoped npm tokens with mandatory 2FA on publish; rotate on any suspicion.
- Restrict IMDS access from build agents (IMDSv2/hop-limit) so a postinstall can't grab cloud creds.
- Pin lockfiles; alert on new transitive versions of high-fan-out packages.
Remediation
- Rotate every secret reachable from affected developer or CI hosts (npm, cloud, Git, SSH).
- Roll back to known-good package versions; purge caches and rebuild agents from clean images.
- Audit and revoke npm tokens; re-enable enforced 2FA for publishing.