Shai-Hulud at Eight Months: Four Variants, One Campaign, and What the npm Ecosystem Has Learned

Written by the Rafter Team

Shai-Hulud is the closest the npm ecosystem has come to a named, persistent, multi-quarter supply-chain campaign. Between September 2025 and May 2026, the same threat actor has shipped four major variants — Shai-Hulud, Shai-Hulud 2.0, Shai-Hulud 3.0, and Mini Shai-Hulud — each adding real engineering improvements over the last. Roughly one variant per quarter.
Reading the four variants as one story produces a clearer picture than any single disclosure: this is a product line, not a series of disconnected attacks. The attackers iterate. The defensive posture has to iterate with it, and the gap between offensive iteration cadence and defensive pattern updates is what determines who wins each variant cycle.
The next Shai-Hulud variant is coming, probably this quarter. The defensive habits that work across all four variants — disabling install-time scripts, pinning dependencies to exact versions with hash verification, and scanning dependencies on every push rather than every audit cycle — work because they target the structural assumptions every variant relies on, not the surface signatures any single variant happens to use today.
The arc
Shai-Hulud — September 2025
The first true npm worm. Self-propagating, token-harvesting, named after the Dune sandworms. The attack pattern: compromise a maintainer account (typically via token theft), use that maintainer's npm publish credentials to push poisoned versions of every package they own, harvest credentials from every machine running npm install against those poisoned versions, use the harvested credentials to compromise more maintainer accounts. Recursion.
The original variant established the campaign's tradecraft: postinstall-hook execution, credential collectors targeting ghp_ / gho_ / npm_ token prefixes, GitHub-based exfiltration channels, and the Dune-themed naming that gave the campaign its identity.
Shai-Hulud 2.0 — November 2025
Significantly larger blast radius. Datadog Security Labs documented ~25,000 poisoned repositories across roughly 350 unique users by the end of the second variant's run.
The 2.0 variant added a "dead man's switch" — an exfil threat structured so that if the attacker's connection to a compromised system was severed, the worm would attempt destructive operations against the victim's data. This was the first variant to use the threat of destructive payload as leverage, rather than purely as silent extraction.
Naming convention held: attacker-controlled exfil repositories used Dune-themed names and descriptions.
Shai-Hulud 3.0 — December 2025
Surfaced through a single malicious package, @vietmoney/react-big-calendar@0.26.2. Limited initial distribution — likely a controlled test deployment of the new code before wider release.
Technical improvements over 2.0:
- Reorganized file structure with renamed installer and payload components.
- Improved obfuscation of the JavaScript payload.
- Broader cross-platform compatibility, including better Windows support.
- New GitHub repository description strings used in exfil drops, replacing earlier identifiers — likely an attempt to evade detection methods built on the 2.0 string set.
- Improved error handling and more modular code, which security researchers describe as resilience improvements.
Mini Shai-Hulud — April 2026
The most recent variant. Codenamed "Mini" because it ships a tighter-scoped credential collection surface (five collectors instead of seven), but architecturally the most evolved variant to date.
Mechanics:
- Two-stage Bun-runtime bootstrap. A small initial dropper downloads the Bun JavaScript runtime from GitHub releases — cross-platform across Linux x64/arm64/musl, macOS x64/arm64, and Windows x64/arm64. Bun executes the actual obfuscated payload.
ctf-scramble-v2cipher family, carried over from the Bitwarden CLI compromise of late 2025.- GitHub-as-C2 dead drop using commit-search retrieval — credentials encoded into commit messages with a campaign-specific prefix, pushed to attacker-controlled repos, retrieved later via GitHub's commit-search API.
- Russian-language kill switch: the malware refuses to execute on hosts with Russian configured as a system language. A strong but not definitive attribution signal.
Mini Shai-Hulud has compromised SAP CAP npm packages on April 29, 2026 and PyTorch Lightning 2.6.2 / 2.6.3 on April 30, 2026. The Lightning hit added a notable cover-story escalation: every poisoned commit pushed to victim repositories is authored under a hardcoded identity designed to impersonate Anthropic's Claude Code.
Three observations no single disclosure produces
The campaign iterates like a product
Each variant adds real engineering improvements — better obfuscation, broader platform support, smaller and more resilient credential collectors, modular code structure, improved error handling. None of these are flourishes; they all reduce the rate at which the variant gets detected, the cost of running it on new platforms, and the fragility of its exfil channels.
The cadence is roughly one major variant per quarter. That is a faster release cadence than most defensive security tools update their pattern libraries on. Detection-engineering teams that pattern-match on a previous variant's strings find the current one has rotated them.
The cover story is climbing the trust stack
- Shai-Hulud 1.0 used random repository names.
- Shai-Hulud 2.0 used Dune-themed repository names.
- Shai-Hulud 3.0 rotated to new GitHub repository descriptions to evade string-based detection.
- Mini Shai-Hulud uses "EveryBoiWeBuildIsAWormyBoi" as its commit-search dead-drop prefix and "A Mini Shai-Hulud has Appeared" as its attacker-repo description.
- Lightning Mini Shai-Hulud authors poisoned commits under a hardcoded Anthropic Claude Code identity.
The trajectory is from generic, to themed, to a recognized AI-developer-tool brand. Each step is harder to detect because each step looks more like a routine artifact of how developers work today. A repository named random-utils raises eyebrows. A commit authored as claude-code does not.
Defensive cycle time is the wrong metric
Each Shai-Hulud variant is detected and quarantined within hours of disclosure. npm has gotten dramatically better at this; PyPI is improving. Average time-to-quarantine on the variants we have hard numbers for sits in the low tens of minutes to hours.
That number, on its own, looks good. But it is not the relevant window.
The relevant window is the gap between attacker iteration and defensive pattern updates. Four major variants in eight months means the campaign ships slightly faster than quarterly. Detection rules built on variant N are stale when variant N+1 ships, and the gap between "variant ships" and "rules updated for the new variant" is measured in days at best.
Defensive tooling built on signature detection is, structurally, one variant behind for the entire life of the campaign.
What this means for defenders
The right response is not to chase the variant. It is to harden the primitive the campaign keeps exploiting.
Every Shai-Hulud variant has the same load-bearing assumption: that developers run dependencies with install-time execution privileges, against lockfiles that move when a new version is published, on machines that hold credentials with wider scope than the install itself requires.
Each of those assumptions is fixable.
Turn off install-time scripts
npm config set ignore-scripts true. Re-enable only for specific packages where you've audited the install hook. The next Shai-Hulud variant will not abandon postinstall hooks; they are too useful. Turning them off across the board defeats the entire delivery mechanism, regardless of which variant is current.
For Python, the equivalent is treating import-time side effects as suspicious and using virtual environments aggressively. The PyTorch Lightning compromise specifically used import-time execution; the same defensive posture applies.
Pin to exact versions and verify hashes
A worm whose value proposition is silent compromise of new releases is defeated by a lockfile that does not move. package-lock.json with --frozen-lockfile, or pip install --require-hashes, is the structural defense.
The cost is that you have to actively update dependencies, with review, rather than receiving them as a side effect of npm install. That cost is the point. The friction is the defense.
Scan dependencies on every push
Audit-mode dependency scans run on a cadence — typically nightly, weekly, or per-release. The campaign ships faster than that.
The diff that introduces a new dependency, or that updates a dependency to a poisoned version, is where the warning is most useful. Rafter's Code Analysis Engine flags known-vulnerable versions on every push. Mini Shai-Hulud's quarantine window for the Lightning compromise was about 42 minutes. A push-time scanner closes the gap between "advisory exists" and "the next merge is blocked."
Scope your tokens narrowly
Every Shai-Hulud variant harvests broad-scope credentials. A repo-write npm publish token is worth significantly more to the worm than a read-only token. Use single-purpose tokens with the minimum scope each tool needs.
The variants will keep finding tokens to steal. The question is what those tokens are good for once stolen.
Closing on the cadence
Shai-Hulud is the case study for how a supply-chain campaign behaves when it is treated as a product line rather than a one-off. Four variants in eight months. Each variant adding real engineering. The cover story climbing the trust stack toward AI-developer-tool brand impersonation. The defensive cycle running slightly behind the offensive cycle on every metric.
The next variant is coming. Probably this quarter. Plan around the campaign, not the disclosure.
Further reading
- PyTorch Lightning, Mini Shai-Hulud, and Malware That Signs Commits as Claude Code — the most recent variant's most visible compromise.
- Sandworm-mode: the npm worm that injected MCP servers — a related but distinct AI-tool-targeting npm worm in the same era.
- Three Supply Chains, One Trust Relationship — the broader trust-relationship pattern Shai-Hulud variants exploit.
Sources
- Upwind — Shai-Hulud 3.0: npm Supply Chain Worm Reappears With Enhanced Obfuscation: https://www.upwind.io/feed/shai-hulud-3-npm-supply-chain-worm
- Kodem — Guess Who's Back: Shai-Hulud 3.0 The Golden Path: https://www.kodemsecurity.com/resources/guess-whos-back-shai-hulud-3-0-the-golden-path
- Datadog Security Labs — Shai-Hulud 2.0 npm worm analysis: https://securitylabs.datadoghq.com/articles/shai-hulud-2.0-npm-worm/
- ReversingLabs — New Shai-Hulud worm spreads: What to know: https://www.reversinglabs.com/blog/new-shai-hulud-worm-spreads-what-to-know
- Endor Labs — Mini Shai-Hulud: npm Worm Hits SAP Developer Packages: https://www.endorlabs.com/learn/mini-shai-hulud-npm-worm-hits-sap-developer-packages
- Mondoo — Shai-Hulud Strikes Back, with v3.0: https://mondoo.com/blog/shai-hulud-strikes-back-with-v3-0-the-evolution-of-a-potent-and-persistent-npm-supply-chain-worm
- The TeamPCP campaign retrospective
- Wallet-stealer payloads in package ecosystems
- A year of AI developer-tool supply-chain attacks