NPM Supply Chain Security Scanner
Security toolkit for detecting supply chain vulnerabilities in NPM projects, designed to detect patterns from the major 2025-2026 npm supply chain attacks:
- CVE-2025-54313 (Scavenger malware - July 2025)
- Shai-Hulud worm (September 2025) and Shai-Hulud 2.0 "The Second Coming" (November 2025)
- Mini Shai-Hulud / TeamPCP family (April-June 2026): SAP CAP, Bitwarden CLI, TanStack (CVE-2026-45321), AntV, Miasma (Red Hat), Hades (PyPI)
Purpose
Detect and notify security vulnerabilities in NPM (and now PyPI) dependencies, including:
- 1340+ compromised package versions (Shai-Hulud v1/v2 + CVE-2025-54313 + the 2026 Mini Shai-Hulud waves)
- Cross-ecosystem coverage: npm + PyPI (Hades wave), with Maven spillover documented
- Bun-runtime loaders used for EDR evasion (
setup.mjs,execution.js,bw1.js,_index.js, pinned Bun v1.3.13) - Malware persistence via agent/IDE config files (survives
npm uninstall) - OIDC / Trusted-Publishing abuse and GitHub commit-pinned tarball injection
- Shai-Hulud 2.0 Bun payloads (
setup_bun.js,bun_environment.js) - Typosquatting attempts
- Injected malicious code (DLL/SO files, obfuscated scripts)
- Suspicious installation scripts
- Worm-like/propagation behaviors
- C2 domain communication
- Cloud metadata endpoint (IMDS) access
Files
npm-supply-chain-detector.py- Main Python detection scriptscan-npm-security.sh- Bash automation and monitoring scriptmalicious-patterns.json- Malicious patterns database (production)shai-hulud-iocs.json- Extended IOCs database (740+ packages / 1340 versions, 29 hashes, C2 domains, 2026 Mini Shai-Hulud + PyPI Hades sections)update-patterns.py- Pattern database generator/updater
Installation
# Clone or download scripts
chmod +x npm-supply-chain-detector.py scan-npm-security.sh
# Check prerequisites
./scan-npm-security.sh --help
Prerequisites
- Python 3.6+
- npm/node installed
- NPM project with package.json
Usage
Simple scan
# Scan current directory
python3 npm-supply-chain-detector.py
# Scan specific project
python3 npm-supply-chain-detector.py /path/to/project
# With detailed report
python3 npm-supply-chain-detector.py -v -o markdown -f report.md
Automation script
# Basic scan
./scan-npm-security.sh
# Continuous monitoring (scan every 5 minutes)
./scan-npm-security.sh -c -i 300
# Deep scan with save
./scan-npm-security.sh -d -f security-report.md -o markdown /project
# With webhook notifications (Slack, Discord, etc.)
./scan-npm-security.sh -w https://hooks.slack.com/services/XXX
# Quarantine suspicious packages (moves to .npm-quarantine/)
./scan-npm-security.sh --quarantine
# Restore quarantined packages if false positive
./.npm-quarantine/restore.sh
Available options
Python Script (npm-supply-chain-detector.py)
-o, --output: Output format (json, text, markdown)-f, --file: Save report to file-v, --verbose: Verbose mode--webhook: Webhook URL for notifications
Bash Script (scan-npm-security.sh)
-c, --continuous: Continuous monitoring mode-i, --interval: Interval between scans (seconds)-d, --deep: Deep scan (includes npm audit, outdated packages)--quarantine: Move suspicious packages to quarantine folder--update-patterns: Update patterns from file
Quarantine Feature
The --quarantine option automatically isolates compromised packages:
How it works:
- Scans for critical vulnerabilities
- Identifies compromised packages from scan results
- Moves packages from
node_modules/to.npm-quarantine/packages/ - Creates JSON manifest with metadata (versions, paths, timestamps)
- Generates automatic
restore.shscript
Directory structure created:
.npm-quarantine/
├── packages/ # Isolated packages
│ ├── package-name/
│ └── @scope_package-name/
├── logs/ # Scan logs
├── quarantine-manifest-*.json # Metadata
└── restore.sh # Restoration script
To restore (if false positive):
cd .npm-quarantine
./restore.sh # Interactive confirmation required
Detections
1. Known compromised packages (1340 versions)
CVE-2025-54313 (Scavenger - July 2025):
- eslint-config-prettier (8.10.1, 9.1.1, 10.1.6, 10.1.7)
- eslint-plugin-prettier (4.2.2, 4.2.3)
- synckit (0.11.9)
- @pkgr/core (0.2.8)
- napi-postinstall (0.3.1)
- got-fetch (5.1.11, 5.1.12)
- is (3.3.1, 5.0.0)
- @crowdstrike/node-exporter (0.2.2)
- @crowdstrike/threat-center (1.205.2)
- tailwind-toucan-base (5.0.2)
- Shai-Hulud 2.0 (Wiz, Nov 27 2025): ~470 packages / versions (e.g.
@asyncapi/*,@actbase/*,@accordproject/*,@antstackio/*, etc.) – seeshai-hulud-iocs.jsonfor the full list
Shai-Hulud worm (September 2025):
- CrowdStrike packages (@crowdstrike/*)
- @ctrl/tinycolor (4.1.1, 4.1.2)
- @nativescript-community/* packages
- @operato/* packages
- @things-factory/* packages
- Many others (see shai-hulud-iocs.json)
Shai-Hulud 2.0 (November 2025, Unit42 & Wiz)
- New payloads:
setup_bun.js,bun_environment.js - bun_environment.js hashes:
62ee164b9b306250c1172583f138c9614139264f889fa99614903c12755468d0,f099c5d9ec417d4445a0328ac0ada9cde79fc37410914103ae9c609cbc0ee068,cbb9bc5a8496243e02f3cc080efbe3e4a1430ba0671f2e43a202bf45b05479cd - setup_bun.js hash:
a3894003ad1d293ba96d77881ccd2071446dc3f65f434669b49b3da92421901a - GitHub exfiltration: repo description "Sha1-Hulud: The Second Coming"
- Possible destructive fallback (
rm -rf ~/$HOME)
Mini Shai-Hulud / TeamPCP family (April-June 2026)
Threat actor TeamPCP (aka UNC6780), who open-sourced their "Mini Shai-Hulud" malware, triggering a cascade of waves (and copycats). All of them use a Bun loader (EDR evasion) and exfiltrate via GitHub dead-drop repositories created on the victim's own account:
| Wave | Date | Ecosystem | Key packages |
|---|---|---|---|
| Bitwarden CLI ("The Third Coming") | 2026-04-22 | npm | @bitwarden/[email protected] (via Checkmarx breach) |
| SAP CAP ("A Mini Shai-Hulud has Appeared") | 2026-04-29 | npm | mbt, @cap-js/sqlite, @cap-js/postgres, @cap-js/db-service |
| TanStack (CVE-2026-45321) | 2026-05-11 | npm + PyPI | 42 @tanstack/* pkgs, @mistralai/mistralai, @uipath/cli (OIDC/Trusted-Publishing hijack, valid SLSA provenance) |
| AntV ("Here We Go Again") | 2026-05-19 | npm | @antv/g2,g6,l7,s2, echarts-for-react, timeago.js, size-sensor (compromised atool maintainer account) |
| Miasma ("The Spreading Blight") | 2026-06-01 | npm | @redhat-cloud-services/* (via GitHub Actions OIDC) |
| Hades ("The End for the Damned") | 2026-06-07 | PyPI | 19 projects via *-setup.pth hook → Bun → _index.js |
Novel TTPs covered: Bun v1.3.13 runtime (evasion), persistence via agent/IDE config files (.claude/.vscode/.cursor, survives npm uninstall), OIDC/Trusted-Publishing abuse, "living-off-trusted-host" exfiltration (api.anthropic.com/v1/api, filev2.getsession.org), and destructive wipe triggered on token invalidation.
2. Typosquatting detection
- Levenshtein distance analysis
- Common substitutions (0→o, 1→i, etc.)
- Dash/underscore variations
3. Malicious code patterns
- Credential exfiltration (AWS, npm, SSH, GitHub tokens)
- Remote code execution (curl|sh, eval)
- Obfuscation (base64, atob, XOR encryption)
- Suspicious network communication to C2 domains
- Self-propagation (worm patterns, npm publishing)
- Cloud metadata endpoint (IMDS) access
- CVE-2025-54313 specific: DLL/SO loading, logDiskSpace function
4. Suspicious installation scripts
- Malicious preinstall/postinstall hooks
- Script download and execution
- npm token manipulation
- Windows DLL execution (rundll32, regsvr32)
- Malicious files: node-gyp.dll, loader.dll, version.dll
5. Hash-based detection (29 variants)
- Shai-Hulud bundle.js (7 SHA-256 hashes)
- Shai-Hulud 2.0 Bun payloads:
bun_environment.js(3 hashes),setup_bun.js(1 hash) - CVE-2025-54313 Scavenger (3 SHA-256 hashes)
- node-gyp.dll: c68e42f416f482d43653f36cd14384270b54b68d6496a8e34ce887687de5b441
- Scavenger stage 2: 5bed39728e404838ecd679df65048abcb443f8c7a9484702a2ded60104b8c4a9
- install.js: 32d0dbdfef0e5520ba96a2673244267e204b94a49716ea13bf635fa9af6f66bf
6. C2 domain detection
- firebase.su (CVE-2025-54313)
- dieorsuffer.com (CVE-2025-54313)
- smartscreen-api.com (CVE-2025-54313)
- npnjs.com (typosquatting)
- webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7 (Shai-Hulud)
- t.m-kosche.com (Mini Shai-Hulud AntV C2)
- filev2.getsession.org, api.masscan.cloud, git-tanstack.com (TanStack wave)
- audit.checkmarx.cx (Bitwarden wave exfil)
api.anthropic.com/v1/api— path-only detection (host is legitimate, abused via bogus path; never blocked outright)
7. Integrity analysis
- Verification via
npm audit - Large JS file detection (>3MB)
- npm domain validation
Report formats
JSON
{
"scan_date": "2025-01-22T10:30:00",
"project_path": "/path/to/project",
"findings": [
{
"severity": "critical",
"message": "KNOWN COMPROMISED PACKAGE",
"location": "package.json",
"details": {...}
}
],
"statistics": {
"total_findings": 5,
"critical": 2,
"warning": 3
}
}
Markdown
Formatted report with tables and structured sections.
Text
Plain text report for CI/CD integration.
Notifications
Webhook Configuration
Critical findings can be sent to a webhook:
./scan-npm-security.sh -w https://your-webhook-url
Payload format:
{
"text": "NPM Security Alert: X critical vulnerabilities",
"findings": [...]
}
CI/CD Integration
GitHub Actions
- name: NPM Security Scan
run: |
python3 npm-supply-chain-detector.py . -o json -f scan-results.json
if [ $? -ne 0 ]; then
echo "Critical vulnerabilities found!"
exit 1
fi
GitLab CI
npm-security-scan:
script:
- python3 npm-supply-chain-detector.py
artifacts:
reports:
paths:
- security-reports/
Jenkins
stage('Security Scan') {
sh './scan-npm-security.sh -o json -f report.json'
}
Custom configuration
Modify malicious-patterns.json to:
- Add new compromised packages
- Define custom patterns
- Adjust notification thresholds
- Exclude false positives
Continuous monitoring
For 24/7 monitoring:
# With systemd
sudo tee /etc/systemd/system/npm-security-monitor.service << EOF
[Unit]
Description=NPM Security Monitor
After=network.target
[Service]
Type=simple
User=youruser
WorkingDirectory=/path/to/project
ExecStart=/path/to/scan-npm-security.sh -c -i 600 -w https://webhook.url
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl enable npm-security-monitor
sudo systemctl start npm-security-monitor
What to do when detection occurs?
-
Critical findings:
- Use quarantine mode:
./scan-npm-security.sh --quarantine - Immediately isolate compromised packages
- Regenerate all exposed tokens/secrets (npm, GitHub, AWS, SSH keys)
- Audit affected systems for credential exposure
- Check for unauthorized GitHub repositories named "Shai-Hulud"
- Review cloud metadata endpoint (IMDS) access logs
- Use quarantine mode:
-
CVE-2025-54313 specific:
- Check for malicious DLL/SO files (node-gyp.dll, loader.dll, etc.)
- Scan for connections to C2 domains (firebase.su, dieorsuffer.com, smartscreen-api.com)
- Windows systems: Review rundll32/regsvr32 execution logs
-
Warnings:
- Investigate suspicious patterns
- Verify package legitimacy before restoration
- Update to safe versions
- Review package maintainer changes
-
Post-incident:
- Replace with safe package versions:
npm install <package>@<safe-version> npm audit fixfor automatic fixes- Dependency review and lockfile verification
- Set up continuous monitoring (
-c -i 300) - Consider restoring from quarantine only after verification
- Replace with safe package versions:
References
- CrowdStrike NPM Attack 2025
- CVE-2025-54313
- CVE-2026-45321 (TanStack / Mini Shai-Hulud)
- Mini Shai-Hulud SAP CAP (StepSecurity)
- Bitwarden CLI hijack (JFrog)
- Shai-Hulud Miasma / Red Hat (Wiz)
- Shai-Hulud Hades PyPI wave (Socket)
- AntV ecosystem compromise (Socket)
- npm audit documentation
Notes
- 1340 compromised package versions tracked across npm + PyPI (updated 2026-06-08)
- 29 malware file hashes detected (Shai-Hulud v1/v2 + Scavenger + 2026 Mini Shai-Hulud waves)
- Multiple attack campaigns covered: CVE-2025-54313, Shai-Hulud v1/v2, and the 2026 Mini Shai-Hulud / TeamPCP family (CVE-2026-45321)
- Scanner designed to minimize false positives (verified against legitimate
.claude/.vscodeconfigs, clean PyPI/npm versions, real Anthropic API calls) - Patterns based on real observed attacks (July 2025 - June 2026)
- Regular update of malicious patterns recommended
- Compatible with all standard NPM projects
- Quarantine feature allows safe isolation with restoration option
Limitations
- Does not replace thorough manual analysis
- May not detect zero-day attacks
- Performance dependent on project size
- Requires read permissions on node_modules
Contributing
To add new patterns or compromised packages:
-
Update pattern files:
- Edit
update-patterns.pyto add new packages/patterns - Run
python3 update-patterns.pyto regenerateshai-hulud-iocs.json - Or manually edit
malicious-patterns.jsonfor quick updates
- Edit
-
Test changes:
python3 npm-supply-chain-detector.py -v test-project/ -
Update documentation:
- Update statistics in
README.md
- Update statistics in