A Python tool to scan your GitHub organizations' repositories for indicators of compromise (IOCs) related to the Shai-Hulud npm supply chain attack.
The Shai-Hulud attack is an ongoing supply chain attack targeting npm packages. It compromises packages to exfiltrate sensitive data (environment variables, secrets, tokens) from development environments and CI/CD pipelines.
- Malicious Files - Known malicious files like
setup_bun.js,bun_environment.js,bundle.js - Malicious Branches - Checks for
shai-huludbranches - Compromised Packages - Dependencies known to be infected (fetched from external sources)
- Suspicious Scripts -
preinstall/postinstallscripts with exfiltration patterns - Malicious Workflows - GitHub Actions workflows containing suspicious patterns
- Known Malicious Hashes - Checks file SHAs against known malicious hashes
- Auto-updating IOCs - Fetches the latest compromised package list from external sources
- Local caching - Caches IOCs locally for 24 hours to reduce network calls
- Fallback list - Uses a hardcoded fallback if external sources are unavailable
- Multiple sources - Tries multiple external IOC sources for reliability
cd shai-hulud-scanner
pip install -r requirements.txt# Set your GitHub Personal Access Token
export GITHUB_TOKEN=ghp_your_token_here
# Scan all your organizations
python shai_hulud_scanner.py
# Scan specific organizations
python shai_hulud_scanner.py --orgs myorg1 myorg2
# Scan personal repos only
python shai_hulud_scanner.py --personal-only
# Include personal repos with org repos
python shai_hulud_scanner.py --include-personal# Force refresh IOC list from external sources
python shai_hulud_scanner.py --refresh-iocs
# List all known compromised packages
python shai_hulud_scanner.py --list-iocs# Output findings to JSON
python shai_hulud_scanner.py --output report.json| Flag | Description |
|---|---|
--token, -t |
GitHub PAT (or set GITHUB_TOKEN env var) |
--orgs, -o |
Specific organizations to scan |
--personal-only |
Only scan personal repositories |
--include-personal |
Include personal repos with org repos |
--output, -O |
Output JSON report file |
--verbose, -v |
Show all repos, not just those with issues |
--skip-archived |
Skip archived repositories |
--refresh-iocs |
Force refresh IOC list from external sources |
--list-iocs |
List all known compromised packages and exit |
This scanner does NOT maintain any hardcoded IOC lists. All indicators of compromise are fetched from external security researchers who actively track the attack.
The scanner tries these sources (in order):
- StepSecurity GitHub - Comprehensive IOC data including packages, files, patterns
- Cobenian shai-hulud-detect - Community detection project
- Socket.dev - Professional malware database
If ALL external sources fail, the scanner will error out rather than use stale data. This ensures you're always scanning against the latest threat intelligence.
IOCs are cached locally at ~/.cache/shai-hulud-scanner/iocs.json for 6 hours.
Your Personal Access Token needs these scopes:
repo- Full control of private repositories (to read contents)read:org- Read organization membership
| Level | Description |
|---|---|
| 🚨 Critical | Known malicious files/branches detected (active compromise) |
| 🔴 High | Suspicious files or compromised packages in dependencies |
| 🟠 Medium | Suspicious scripts in package.json |
| 🟡 Low | Suspicious patterns in workflows |
| ✅ None | No issues detected |
If the scanner finds issues:
- Remove malicious files - Delete any files identified in the scan
- Delete malicious branches - Remove any malicious branches identified
- Remove compromised packages - Update
package.jsonto remove infected packages - Clean install - Delete
node_modulesandpackage-lock.json, then reinstall - Rotate secrets - Assume ALL environment variables and secrets are compromised
- Review workflows - Check GitHub Actions for unauthorized changes
- Block exfil domains - Block outbound connections to domains identified in scan
- Enable Dependabot alerts
- Use
npm auditin CI/CD pipelines - Pin dependencies to specific versions
- Review and limit GitHub App permissions
- Implement least-privilege for CI/CD tokens
Important: This scanner intentionally does NOT maintain any hardcoded IOC lists.
Why? Security researchers at StepSecurity, Socket.dev, and others are actively tracking this attack and updating their databases. They do this better than any static list we could maintain.
If external sources are unavailable, the scanner will fail rather than give you a false sense of security with outdated data.
📋 Loading Indicators of Compromise...
🌐 Fetching compromised package list from external sources...
Trying StepSecurity GitHub... ✅ Found 156 packages
✅ Loaded 156 compromised packages (source: StepSecurity GitHub)
🔍 Scanning 150 repositories for Shai-Hulud indicators...
--------------------------------------------------------------------------------
🚨 myorg/infected-repo [CRITICAL]
URL: https://github.com/myorg/infected-repo
🔥 MALICIOUS FILES/BRANCHES DETECTED:
- branch:shai-hulud (⚠️ KNOWN MALICIOUS)
- setup_bun.js (⚠️ KNOWN MALICIOUS)
🔴 myorg/backend-api [HIGH]
URL: https://github.com/myorg/backend-api
📦 COMPROMISED PACKAGES:
- @poppinss/colors@3.0.0
- posthog-node@2.1.0
================================================================================
SCAN SUMMARY
================================================================================
IOC Source: StepSecurity GitHub
Total repositories scanned: 150
Node.js repositories found: 45
Repositories with issues: 2
Risk Breakdown:
🚨 Critical: 1
🔴 High: 1
🟠 Medium: 0
🟡 Low: 0
⚠️ IMMEDIATE ACTION REQUIRED!
MIT