Incident Response & Protection Guide for npm Supply Chain Attacks Defense guide for detection & remediation against npm supply-chain worms | Shai-Hulud 2.0 (November 2025) and future threats
π΄ Shai-Hulud 2.0 contains a destructive fallback mechanism!
If the malware cannot exfiltrate data or propagate (no GitHub/npm token, blocked network), it will OVERWRITE AND DELETE ALL WRITABLE FILES IN YOUR HOME DIRECTORY.
- Forcefully disconnect from the internet without backup
- Block all network traffic immediately
- Kill suspicious processes without proper isolation
- Backup first β If possible, copy critical data before any action
- Selective network isolation β Block outbound except GitHub API
- Evidence collection β Preserve logs before cleanup
- Follow remediation carefully β See docs/REMEDIATION.md
This is not theoretical β the wiper code has been confirmed by multiple security researchers.
npm is revoking ALL legacy (classic) tokens on December 9, 2025 as a direct response to Shai-Hulud attacks.
npm token listOption 1: Trusted Publishing (Recommended)
# .github/workflows/publish.yml
- uses: actions/setup-node@v4
with:
registry-url: 'https://registry.npmjs.org'
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Option 2: Granular Tokens
- Max lifetime: 90 days (default 7 days)
- Scope to specific packages only
- Enable IP allowlist if possible
π npm Token Migration Guide
If you suspect you're compromised, run this immediately:
# One-liner β no installation needed
npx huludOr scan a specific directory:
npx hulud scan /path/to/your/projectnpx hulud # Scan current directory
npx hulud scan . # Same as above
npx hulud check # Quick check (alias for scan .)
npx hulud scan --all # Scan all detected dev directories
npx hulud scan --system # Scan system locations (~/.npm, ~/.bun, etc.)
npx hulud scan --deep # Deep scan of entire HOME (slow!)
npx hulud suspend # Safely freeze malicious processes (SIGSTOP)
npx hulud info # Show attack info and IOCs
npx hulud --help # Show all optionsScan options:
--allβ Auto-detect and scan Dev, Projects, Code, repos, src, workspace--systemβ Scan ~/.npm, ~/.bun, ~/.config, ~/.cache, npm global--deepβ Deep scan of entire HOME directory (slow!)--dry-runβ Preview what would be scanned--parallel Nβ Number of parallel jobs (default: 4)
git clone https://github.com/miccy/dont-be-shy-hulud.git
cd dont-be-shy-hulud
./scripts/detect.sh /path/to/your/project- What is Shai-Hulud 2.0?
- Am I Affected?
- Roadmap
- Immediate Actions
- Detection Scripts
- Remediation Guide
- Hardening Your Environment
- Tool Configuration
- Resources
Shai-Hulud 2.0 (aka "The Second Coming") is a self-propagating npm worm discovered on November 24, 2025. It represents a significant evolution in supply chain attacks.
| Date | Event | Source |
|---|---|---|
| Aug 27, 2025 | S1ngularity/Nx GitHub token theft (precursor) | Unit42 |
| Sep 15, 2025 | Shai-Hulud v1 discovered (postinstall-based) | Aikido |
| Sep 23, 2025 | CISA Advisory issued | CISA |
| Nov 5, 2025 | npm disables new classic token creation | GitHub |
| Nov 21-23, 2025 | Shai-Hulud 2.0 packages uploaded | Multiple |
| Nov 24, 2025 03:16 UTC | First detection (go-template, AsyncAPI) | Wiz |
| Nov 24, 2025 04:11 UTC | PostHog packages compromised | PostHog |
| Nov 24, 2025 05:09 UTC | Postman packages compromised | Postman |
| Nov 24, 2025 | Peak: 1,000 new repos every 30 minutes | Datadog |
| Nov 25, 2025 | 800+ packages, 25,000+ repos, 1,200+ orgs, 20M+ weekly downloads | Wiz, Check Point |
| Nov 25, 2025 | Secondary phase detected ("Continued Coming") | Wiz |
| Nov 26, 2025 | GitHub reduces public malicious repos to ~300 | GitHub |
| Dec 02, 2025 | Community detection tools matured (don't-be-shy-hulud v1.5.0 released) | Community |
| Dec 9, 2025 | npm legacy token revocation deadline | npm |
| Feature | v1 (September) | v2 (November) |
|---|---|---|
| Execution Phase | postinstall |
preinstall |
| Exfiltration | Webhook endpoint | GitHub repos |
| Runtime | Node.js | Bun |
| Fallback | None | Dead-man switch (wipe data) |
| Persistence | None | GitHub Actions backdoor |
| Propagation | ~500 packages | 800+ packages (20M+ downloads) |
flowchart TD
subgraph INFECTION["1. Initial Infection"]
A[Compromised npm package] --> B[preinstall script executes]
B --> C[Drops setup_bun.js + bun_environment.js]
end
subgraph PAYLOAD["2. Payload Execution"]
C --> D[Installs Bun runtime]
D --> E[Runs 10MB+ obfuscated payload]
end
subgraph HARVEST["3. Credential Harvesting"]
E --> F[~/.npmrc - npm tokens]
E --> G[~/.aws, ~/.azure, ~/.config/gcloud]
E --> H[Environment variables]
E --> I[GitHub Actions secrets]
E --> J[TruffleHog scan for secrets]
end
subgraph EXFIL["4. Exfiltration"]
F & G & H & I & J --> K[Creates public GitHub repo]
K --> L["Description: Sha1-Hulud: The Second Coming"]
K --> M["Random 18-char name: [0-9a-z]{18}"]
end
subgraph PROPAGATE["5. Propagation"]
L --> N[Uses stolen npm token]
N --> O[Publishes infected versions]
O --> P[Up to 100 packages per victim]
P --> Q[Cross-victim token reuse]
end
subgraph PERSIST["6. Persistence"]
Q --> R[GitHub Actions workflow backdoor]
R --> S[Triggered via repository discussions]
end
subgraph FALLBACK["7. Dead Man's Switch"]
T{Exfiltration blocked?}
T -->|Yes| U[π Wipes user data]
T -->|No| V[β
Attack continues]
end
S --> T
Q --> T
style INFECTION fill:#ff6b6b,color:#fff
style PAYLOAD fill:#feca57,color:#000
style HARVEST fill:#48dbfb,color:#000
style EXFIL fill:#ff9ff3,color:#000
style PROPAGATE fill:#54a0ff,color:#fff
style PERSIST fill:#5f27cd,color:#fff
style FALLBACK fill:#ee5a24,color:#fff
π Text version (for terminals without Mermaid support)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SHAI-HULUD 2.0 ATTACK FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. INITIAL INFECTION β
β βββ Compromised npm package with preinstall script β
β βββ Drops: setup_bun.js + bun_environment.js β
β β
β 2. PAYLOAD EXECUTION β
β βββ Installs Bun runtime (evades Node.js monitoring) β
β βββ Runs 10MB+ obfuscated payload β
β β
β 3. CREDENTIAL HARVESTING β
β βββ ~/.npmrc (npm tokens) β
β βββ ~/.aws/, ~/.azure/, ~/.config/gcloud/ β
β βββ Environment variables β
β βββ GitHub Actions secrets β
β βββ TruffleHog scan for secrets in codebase β
β β
β 4. EXFILTRATION β
β βββ Creates public GitHub repo with stolen data β
β βββ Description: "Sha1-Hulud: The Second Coming" β
β βββ Random 18-char name: [0-9a-z]{18} β
β β
β 5. PROPAGATION β
β βββ Uses stolen npm token to publish infected versions β
β βββ Up to 100 packages per victim β
β βββ Cross-victim: uses other victims' tokens β
β β
β 6. PERSISTENCE β
β βββ GitHub Actions workflow backdoor β
β βββ Triggered via repository discussions β
β β
β 7. FALLBACK (if blocked) β
β βββ Dead-man switch: wipes user data β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Check for IOC files
find . -name "setup_bun.js" -o -name "bun_environment.js" 2>/dev/null
# Check for malicious workflows
find . -path "*/.github/workflows/*" -name "*.yml" -exec grep -l "SHA1HULUD\|self-hosted" {} \;
# Check npm cache
npm cache ls 2>/dev/null | grep -E "(setup_bun|bun_environment)"If you use any of these packages, immediately audit your lockfile:
| Package | Risk | Notes |
|---|---|---|
@postman/tunnel-agent |
π΄ Critical | 27% of environments |
posthog-node |
π΄ Critical | 25% of environments |
posthog-js |
π΄ Critical | 15% of environments |
@asyncapi/specs |
π΄ Critical | 20% of environments |
@asyncapi/openapi-schema-parser |
π΄ Critical | 17% of environments |
@zapier/* |
π΄ Critical | Multiple packages |
@ensdomains/* |
π΄ Critical | Multiple packages |
@postman/postman-mcp-cli |
π High | MCP tooling |
zapier-sdk |
π High | |
angulartics2 |
π High | |
koa2-swagger-ui |
π High | |
tinycolor2 |
π High | v4.1.2 specifically (note: tinycolor2, not tinycolor) |
ngx-bootstrap |
π High | Angular bootstrap components |
@zapier/zapier-sdk |
π΄ Critical | v0.15.5-0.15.7 |
For full IOC database with detailed indicators, see IOC Lists below and ioc/malicious-packages.json.
# 1. STOP - Don't run npm install on any project
# 2. Disconnect from network if possible
# 3. Check for exfiltration repos on your GitHub
# Search: https://github.com/search?q=Sha1-Hulud+user%3AYOUR_USERNAME
# 4. Revoke ALL tokens immediately
npm token revoke $(npm token ls --json | jq -r '.[].key')
# 5. Rotate credentials
# See: docs/REMEDIATION.md# 1. Freeze npm updates
# Add to .npmrc:
echo "ignore-scripts=true" >> ~/.npmrc
# 2. Clear caches
rm -rf node_modules
npm cache clean --force
# or for bun:
rm -rf node_modules bun.lockb
bun pm cache rm
# 3. Pin dependencies to known clean versions
# Use dates before Nov 21, 2025./scripts/detect.sh ~./scripts/detect.sh /path/to/project# .github/workflows/security-scan.yml
name: Shai-Hulud Detection
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Shai-Hulud Detector
run: |
curl -sSL https://raw.githubusercontent.com/miccy/dont-be-shy-hulud/main/scripts/detect.sh | bash -s -- .See docs/REMEDIATION.md for detailed steps.
# 1. Identify affected packages
./scripts/detect.sh . --output affected.txt
# 2. Roll back to clean versions
npm install package-name@version-before-nov-21
# 3. Regenerate lockfile
rm package-lock.json
npm install --ignore-scripts
# 4. Verify
npm audit
./scripts/detect.sh .# ~/.npmrc - Recommended settings
ignore-scripts=true
audit=true
fund=falseBun has a known bug: The .npmrc setting ignore-scripts=true does NOT work reliably!
Bun prioritizes its internal trustedDependencies allowlist over .npmrc settings. This means lifecycle scripts may still execute even with ignore-scripts=true in your config.
# ~/.npmrc or .npmrc
ignore-scripts=truebun install --ignore-scripts- name: Install dependencies (Bun)
run: bun install --ignore-scripts # REQUIRED flagWhy This Matters: Shai-Hulud 2.0 specifically installs Bun runtime as an evasion technique because most security tools only monitor Node.js processes.
See configs/renovate-secure.json for a hardened Renovate config that:
- Disables automerge for npm packages
- Increases stabilityDays to 7
- Requires security review labels
- Blocks preinstall/postinstall changes
π For a shared preset you can use across all repos, see miccy/renovate-config:
{ "extends": ["github>miccy/renovate-config"] }This shared preset includes:
- 7-day
stabilityDaysandminimumReleaseAge npm:unpublishSafeprotection- Warnings on Shai-Hulud affected packages
- No automerge for production dependencies
See docs/GITHUB-HARDENING.md for:
- Branch protection rules
- Actions security settings
- Secret scanning configuration
- Code scanning setup
See configs/socket.yml for recommended configuration.
See configs/dependabot.yml for secure settings.
See docs/GITHUB-HARDENING.md for lockdown guide.
| Source | URL |
|---|---|
| Datadog | github.com/DataDog/indicators-of-compromise |
| Wiz Research | wiz-sec-public/wiz-research-iocs |
| Tenable | tenable/shai-hulud-second-coming-affected-packages |
| SafeDep | safedep/shai-hulud-migration-response |
| Cobenian | Cobenian/shai-hulud-detect |
| File | Purpose | Hash (SHA-256) |
|---|---|---|
setup_bun.js |
Loader/dropper | Various |
bun_environment.js |
Main payload (~10MB) | Various |
actionsSecrets.json |
Exfil data (double base64) | N/A |
.github/workflows/formatter_*.yml |
Backdoor workflow | N/A |
- GitHub repos with description:
Sha1-Hulud: The Second Coming - GitHub repos with random 18-character names matching pattern:
[0-9a-z]{18} - GitHub Actions runners named
SHA1HULUD - Files:
cloud.json,contents.json,environment.json,truffleSecrets.json .truffler-cachedirectory- Bun installation in unexpected locations
- HackerOne Blog
- Socket.dev Analysis
- Datadog Security Labs
- Wiz Research
- GitLab Security
- Palo Alto Unit 42
- GitGuardian
Have questions, found new IOCs, or want to share your experience?
- GitHub Discussions β Ask questions, share findings, get help
- Report Security Issue β For sensitive security reports
- Open an Issue β Bug reports and feature requests
This project is under active development. See our detailed ROADMAP.md for:
- β Completed features
- π§ Work in progress
- π Planned improvements
- π€ Contribution opportunities
Want to help? Pick any unchecked item from the roadmap and submit a PR!
Contributions welcome! Please read CONTRIBUTING.md first.
Priority Areas (see ROADMAP.md for details)
- SIGSTOP suspend script (critical for safe malware handling)
- Expanded IOC database (800+ packages)
- Stack-specific documentation (Expo, Bun, Tauri)
- Network IOCs and file hashes
- SARIF output format
This repository comes with bilingual documentation (English/Czech). To keep only one language:
# Keep only English (removes cs/ folder)
./scripts/set-language.sh en
# Keep only Czech (promotes cs/ files to root)
./scripts/set-language.sh csYou can also do this via GitHub Actions: Go to Actions -> Set Repository Language -> Run workflow.
This project includes VS Code tasks. Press Cmd+Shift+P -> Tasks: Run Task to easily run:
π‘οΈ Quick Auditπ Full Auditπ§Ή Set Language
MIT License - See LICENSE for details.
This guide compiles research from multiple security teams:
- Aikido Security (initial detection)
- Socket.dev, Datadog, Wiz, GitLab, Palo Alto Networks Unit 42
- GitGuardian, SafeDep, Tenable
- The broader security community
Stay safe. Rotate your secrets. Pin your dependencies. π‘οΈ
π Built by @miccy out of hatred for Worms π€¬
