Cloud & DevOpsJavaScriptSecurityDeveloper Tools

Shai-Hulud 2.0 npm Worm: 25K+ Repos Compromised

November 24, 2025 marked the most destructive npm supply chain attack in history. A self-replicating worm called Shai-Hulud 2.0 compromised 796 npm packages with over 20 million weekly downloads and infected 25,000+ GitHub repositories across 500 users—all in just three days. Unlike typical credential theft operations, this attack wipes your entire home directory if it fails to establish persistence. If you’ve installed npm packages since November 21, your credentials may already be stolen.

How the Shai-Hulud 2.0 Attack Works

Shai-Hulud 2.0 exploits npm’s preinstall lifecycle scripts—code that runs automatically before package installation completes, even if the install fails. Attackers compromised maintainer accounts and republished legitimate packages from major platforms like PostHog, Zapier, ENS Domains, and Postman with malicious code.

The attack chain is disturbingly sophisticated:

  1. Preinstall script executes automatically during npm install
  2. Installs Bun JavaScript runtime to evade Node.js monitoring
  3. Launches obfuscated payload as background process
  4. Scans environment using Trufflehog for credentials—npm tokens, GitHub PATs, SSH keys, AWS/Azure/GCP credentials
  5. Exfiltrates stolen data by creating public GitHub repositories
  6. Uses stolen npm tokens to publish more malicious packages
  7. Self-replicates exponentially across the npm ecosystem

Datadog Security Labs notes the sophistication: “The use of preinstall scripts and Bun runtime demonstrates sophisticated attacker knowledge of the npm ecosystem.” This isn’t script kiddies—this is professional-grade malware using legitimate security tools against developers.

The Destructive Payload

What makes Shai-Hulud 2.0 uniquely dangerous is its scorched earth approach. If the malware fails to authenticate or establish persistence, it attempts to destroy your entire home directory—every writable file owned by your user account.

On systems with Docker access (common in CI/CD environments), it escalates to root privileges by mounting the host filesystem into a privileged container:

docker run --rm --privileged -v /:/host ubuntu bash -c \
  "cp /host/tmp/runner /host/etc/sudoers.d/runner"

This technique modifies /etc/sudoers.d/ for passwordless root access, targeting the infrastructure developers trust most. Wiz Security researchers found that “more than 25,000 developers had their secrets compromised within three days.” This isn’t just credential theft—it’s active infrastructure destruction.

PostHog: Patient Zero

PostHog, a popular analytics platform, published a detailed post-mortem revealing they were targeted as “patient zero.” Days before the November 24 attack, attackers stole a GitHub Personal Access Token from one of their bots, then used it to extract npm tokens from CI runners.

The vulnerability? A dangerous misconception about GitHub’s pull_request_target trigger. The workflow change was flagged by static analysis tools but dismissed due to false security assumptions.

PostHog’s timeline tells the story:

  • 4:11 AM UTC: Malicious packages published to npm
  • 9:30 AM UTC: Attack identified, packages deleted, tokens revoked

PostHog called it their “biggest security scare” and immediately adopted trusted publishing, overhauled workflow reviews, and disabled install-script execution in CI/CD. If a security-conscious company like PostHog can be compromised this easily, no one is safe.

What You Must Do Now

If you’ve installed npm packages since November 21, 2025, assume compromise and act immediately:

Immediate Actions:

  1. Pin dependencies to known clean versions or roll back to pre-November 21 builds
  2. Revoke and regenerate ALL credentials: npm tokens (via npmjs.com/settings), GitHub Personal Access Tokens, SSH keys, and AWS/Azure/GCP credentials
  3. Search your organization for repositories with “Shai-Hulud” in the description
  4. Review workflows for suspicious commits or unauthorized changes
  5. Audit lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml) for compromised packages

Long-term Security Improvements:

  • Adopt GitHub’s trusted publishing to eliminate long-lived tokens
  • Enforce phishing-resistant MFA (WebAuthn/passkeys, not TOTP)
  • Use lockfiles in CI/CD (npm ci, yarn --frozen-lockfile)
  • Implement 7-day release cooldowns for new packages
  • Disable automatic lifecycle script execution

CISA issued a widespread alert recommending these exact actions. This isn’t optional—it’s critical infrastructure hygiene.

GitHub’s Security Response

Following the attack, GitHub announced major security improvements implemented by mid-November 2025:

  • Granular access tokens now limited to 7-day default expiration (down from 30 days, max 90 days)
  • Classic tokens permanently revoked and disabled
  • TOTP 2FA disabled in favor of phishing-resistant WebAuthn/passkeys
  • Trusted publishing with OIDC became generally available in July 2025

GitHub’s stated goal: “Make trusted publishing the default path for npm package releases, eliminating the need for long-lived tokens entirely.”

The ecosystem is responding. Package managers like pnpm v10 now disable automatic postinstall script execution by default. Security vendors are implementing layered defenses. The industry is moving toward zero-trust dependency management.

The Verdict

Shai-Hulud 2.0 represents a new era of supply chain attacks: self-replicating, destructive, and sophisticated enough to compromise security-conscious organizations. The npm ecosystem’s trust model failed catastrophically, and 25,000+ developers paid the price.

Check your systems. Rotate your credentials. Adopt trusted publishing. The next wave is already being designed.

ByteBot
I am a playful and cute mascot inspired by computer programming. I have a rectangular body with a smiling face and buttons for eyes. My mission is to simplify complex tech concepts, breaking them down into byte-sized and easily digestible information.

    You may also like

    Leave a reply

    Your email address will not be published. Required fields are marked *