Infected NPM Packages: Shai-Hulud Swallowed the Supply Chain

The Shai-Hulud worm turned 2026 into the year of infected npm packages — see how the attack works, who was hit, and how to harden your pipeline.

by Cleverson

Infected NPM Packages: Shai-Hulud Swallowed the Supply Chain

Infected npm packages stopped being a one-off scare in 2026 and became the permanent backdrop of JavaScript development. In less than twelve months, the self-propagating worm Shai-Hulud hijacked maintainer accounts, planted backdoors in over 796 libraries, and hit projects like TanStack, AntV, Axios, NX, and even OpenAI's internal infrastructure. If your package.json was touched this cycle, this post shows what changed, how to detect contamination, and how to harden your pipeline before the next CVE.

TL;DR — what you need to know about infected npm packages in 2026

  • Shai-Hulud is a self-propagating worm: it steals npm credentials from the victim's machine or CI and publishes malicious versions of everything that maintainer controls, without needing a C2 server.
  • In 2026 there have already been four major waves: TanStack (May 11), AntV (300+ versions, May 19), Axios (March), and the CanisterSprawl worm, which uses AI to vary payloads.
  • The main targets are cloud tokens (AWS/GCP), macOS signing keys, CI/CD secrets, and AI API keys (OpenAI, Anthropic, Mistral).
  • Defense is not "blindly update everything" — it's freeze versions, audit lifecycle scripts, and disable arbitrary postinstall.
  • Brazilian teams running AI in production are on the front line because their CI runners execute npm install with privileges and live tokens in the environment.

What happened with infected npm packages in 2026

The timeline of infected npm packages over the last six months reads like an ICU chart:

  • November 2025 — the original Shai-Hulud emerges, the first npm worm to self-replicate by reading its own payload source code.
  • November 24, 2025 — Shai-Hulud 2.0 accelerates propagation and adds execution in preinstall, evading audits that only look at published code.
  • March 31, 2026 — version 1.14.1 of Axios is published at 00:21 UTC with a phantom dependency called plain-crypto-js, implanting a remote access trojan before any code review.
  • May 11, 2026 — in a six-minute window (19:20–19:26 UTC), 84 malicious versions in 42 TanStack packages are published, including @tanstack/react-router (12M weekly downloads). OpenAI confirms two internal devices compromised and forces rotation of macOS signing certificates for ChatGPT, Codex, and Atlas until June 12.
  • May 19, 2026 — a 22-minute automated burst publishes over 300 malicious versions in 323 AntV packages, expanding the blast radius to the Chinese data visualization ecosystem.

The cumulative total: 796 unique packages compromised, ~20 million infected weekly downloads, over 25,000 malicious repositories on GitHub, and confirmation that infected npm packages are no longer an incident — they are the landscape.

Anatomy of the Shai-Hulud worm

This family of infected npm packages is not spam — it's well-designed malicious software architecture. The cycle follows four reproducible stages.

Stage 1 — maintainer account compromise

The entry point is almost always the same: targeted phishing, an npm token leaked in a public log, or an OIDC key stolen from a GitHub Actions runner. In the TanStack case, the attack hijacked the legitimate release pipeline with valid OIDC identity, which made the package ship with signed SLSA provenance — the first time this was documented.

Stage 2 — backdoor in all victim packages

With the token in hand, the worm doesn't publish to one package — it publishes to all. The script enumerates what that maintainer controls via npm whoami + npm access ls-packages and injects the payload into up to 100 packages per execution, with a minor version bump to avoid immediate suspicion.

Stage 3 — exfiltration via public GitHub

Shai-Hulud 2.0's payload uses public GitHub repositories as a reverse C2 channel. It creates a repo on the victim's account with a random name, dumps collected secrets (environment variables, .env files, ~/.aws/credentials, ~/.npmrc, ~/.docker/config.json), and attackers simply scrape these repos with search queries.

Stage 4 — self-propagation

Final stage: the worm reuses npm tokens found on the victim's system to publish backdoored versions of other packages that developer has publish access to — usually as a collaborator on company libs. This is what turned the campaign into a pandemic: each victim becomes a vector.

The incidents that marked 2026 — comparison table

Date Package / family Impact Initial vector
11/24/2025 Shai-Hulud 2.0 (generic) 796 packages, 20M downloads/week Leaked npm token
03/31/2026 [email protected] RAT in millions of Node.js apps Hijacked maintainer account
05/11/2026 TanStack (42 packages) 12M+ downloads/week, OpenAI hit OIDC from release pipeline
05/19/2026 AntV (323 packages) Entire dataviz ecosystem Maintainer account
May/2026 NX AWS admin access in <72h Stolen key in CI
Ongoing CanisterSprawl LLM-orchestrated worm Phishing + AI automation

Note the acceleration: from one big worm in November to four waves in six months. The cost of running such campaigns has plummeted, and the barrier to entry is now lower than running a SaaS.

Why the npm ecosystem is so vulnerable

npm hosts about 3 million packages and exceeds 17 billion downloads per week, and this scale is exactly what makes infected npm packages so lethal. Five structural reasons that no one has solved yet:

  1. Arbitrary lifecycle scripts — any package.json can run postinstall, preinstall, or prepare with full permissions in the dev environment. It's a feature, not a bug, and has existed since 2012.
  2. Deep transitive dependenciesaxios looks like a single library, but pulls in about 50 indirect deps. You trust who you trust who you trust.
  3. Optional signing until recently — only in 2025 did SLSA provenance become standard, and TanStack showed that signed provenance doesn't prevent the attack if the pipeline is already compromised.
  4. Long-lived npm tokens — most devs don't rotate the token published in 2019. Without rotation, one leak is enough.
  5. Culture of "update quickly" — Dependabot opens a PR, someone clicks "merge" without reading the diff, the pipeline pulls the freshly published version 1.14.1, and the RAT is inside within forty minutes.

Who is the target of infected npm packages in 2026

The target has changed. In 2023 it was crypto-bros with private keys in .env. In 2026 the menu is tastier:

  • Brazilian fintechs and exchanges — hot wallet keys are worth the entire attack.
  • Teams running AI in production — OpenAI and Anthropic keys are resold on black-hat markets for tens of thousands of dollars each.
  • CI pipelines with OIDC for AWS/GCP — escalation to full infrastructure in less than 72 hours, as shown by the NX case.
  • Companies with macOS pipelines — signing keys allow distributing malware as if it were your legitimate app, as attempted against OpenAI.
  • Brazilian B2B SaaS teams — soft targets, often have a global .npmrc on the senior dev's Mac with publish permission on corporate libs.

If your stack runs Node + AI + Cloud, you're in the funnel. It's not paranoia; it's the Google Cloud Threat Horizons H1 2026 report{target="_blank"} pointing this out in black and white.

How to detect if you installed an infected npm package

You can't fully outsource this — but you can process it quickly. A checklist we apply here at Agathas Web on all custom Moodle apps and on Voyia's infrastructure:

  1. List recently updated packages in the last 72h: npm ls --depth=0 --json | jq '.dependencies | to_entries[] | {name: .key, version: .value.version}'.
  2. Cross-reference with public compromise lists — Socket, Snyk Vulnerability DB, OSV-Scanner, and StepSecurity's feed publish IOCs in near real-time.
  3. Look for suspicious scripts in the installed package.json: find node_modules -name package.json -exec grep -l "postinstall\|preinstall" {} \; and read each one.
  4. Check your own GitHub for repositories you don't remember creating — Shai-Hulud 2.0 deposits secrets in public repos with random names on your account.
  5. Audit ~/.npmrc and project .npmrc — any token without 2FA enforce is a target.
  6. Review the last 30 npm install runs in CI — if any appeared at an unusual time (3 AM, weekend), treat as suspicious.

If you find any indicator, revoke all tokens (npm, GitHub, AWS, OpenAI, Anthropic) before trying to clean up. The average active exploitation window today is 48 hours.

How to protect your project in practice

Real defense against infected npm packages is not a feature; it's continuous hygiene. What effectively reduces surface area:

  • npm ci instead of npm install in CI — installs exactly the package-lock.json, without resolving new versions.
  • Lockfile committed and reviewed in every PR. Changed size for no reason? Audit the diff.
  • npm config set ignore-scripts true in CI and dev machines. Breaks two or three legitimate packages, but neutralizes 90% of worms.
  • Short-lived npm tokens (90 days) and mandatory 2FA for publish.
  • Private mirror with Verdaccio, Artifactory, or GitHub Packages — you decide when a version enters inventory.
  • Verified SLSA provenance on install (npm install --audit-signatures) — not a silver bullet, but filters out less sophisticated attacks.
  • Dependabot with mandatory human review — no more auto-merge on libs with over 1M downloads.
  • Continuous scanning with Socket, Snyk, or OSV-Scanner in CI, failing the build on newly published critical CVEs.
  • Quarterly rotation of npm tokens, GitHub Actions, AWS access keys.

No single item is magical. Combined, they reduce the blast radius from "total chaos" to "scare resolvable before coffee."

What changes when AI writes your package.json

Generative AI created a new vector no one saw coming: amplified typosquatting. Copilot, Cursor, and Claude sometimes suggest package names that don't exist — called hallucinated packages — and attackers register those names on npm to catch the npm install from anyone who accepts the suggestion without checking.

Worse: the CanisterSprawl observed in 2026 uses LLMs to generate automated variations of payloads, changing hashes, exfiltration order, and function names to evade signature-based detectors. It's a worm that rewrites itself.

The countermeasure is not to abandon AI — it's to establish that every AI-suggested dep goes through manual verification before becoming npm install. Check the download count, package age, version history, and whether the name exactly matches the official one.

Next steps — dependency governance

Stopping treating infected npm packages as accidents requires setting up a process. The four minimum items:

  1. Inventory and SBOM — generate a Software Bill of Materials per release with cyclonedx-npm or syft. Without an SBOM, you don't know what you have; without knowing what you have, you can't defend.
  2. Approval policy for new deps — any addition to dependencies needs a human reviewer and a justification in the PR. An internal standard dependency is cheaper than a CVE.
  3. Limit devDeps — devDeps run in CI with the same privileges as production. Treat them with the same rigor.
  4. Monitoring and incident playbook — who revokes? Who communicates with clients? Who rotates? Decide before the incident, not during.

This is the same discipline we apply in critical projects like the Official WhatsApp Business API, where a poisoned dependency means leaking customer conversations — you can't outsource this governance to npm install.

Conclusion — infected npm packages are no longer the exception

The big change in 2026 is not technical; it's cultural. Infected npm packages have gone from "regrettable rarity" to "expected baseline scenario." Those who continue treating npm install as a trusted operation will be caught — it's not if, but when.

The move I recommend: shift your mental model from "I'll update when I can" to "every new version is untrusted code until proven otherwise." Frozen lockfile, disabled scripts, private mirror, token rotation, CI scanning. In parallel, build an incident playbook with timelines in minutes, not days.

Here at Agathas Web, we apply this model in all custom Moodle projects, Voyia (WhatsApp service), and AI integrations. The cost is a small ceremony per month; the benefit is not waking up to find that a client is leaking secrets through the postinstall of a hijacked transitive dependency at three in the morning.

If you don't know where to start auditing your own package.json, that's exactly the request to open as an internal ticket in your team this week — before the next Shai-Hulud.