A Docker-based security tool for detecting potentially compromised npm packages in Node.js projects, specifically designed to identify packages affected by the September 2025 npm malware outbreak.
This tool was created in response to a critical ongoing supply chain attack that began on September 15, 2025. The attack has compromised over 580+ package versions from 194+ distinct packages on npm, including popular packages like:
@ctrl/tinycolor
(millions of downloads)- Multiple CrowdStrike-related packages
- Various other widely-used npm packages
The malicious code spreads like a virus through the npm ecosystem:
- Initial Infection: Attackers compromise developer accounts and publish malicious versions of packages
- Code Execution: Infected packages contain a 3.7MB
bundle.js
file that executes during installation via postinstall hooks - Data Exfiltration: The malware:
- Dumps environment variables from infected systems
- Uses TruffleHog to scan for credentials
- Exfiltrates secrets from GitHub repositories
- Uploads stolen data to GitHub repositories and webhooks
- Viral Propagation: Uses stolen npm credentials to infect other packages maintained by compromised developers
- Webhook URL:
https://webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7
- Postinstall hook:
"postinstall": "node bundle.js"
- Large bundle.js file (~3.7MB) in package root
- GitHub workflow files:
.github/workflows/shai-hulud-workflow.yml
- Suspicious repositories named
Shai-Hulud
Source: Endor Labs - npm Malware Outbreak Report
This vulnerability scanner helps you:
- Scan your projects for known compromised packages
- Generate detailed reports of found vulnerabilities
- Log comprehensive activity for audit trails
- Identify affected directories containing vulnerable packages
- Export results in JSON format for further analysis
The tool consists of:
- Python Scanner: Core scanning logic with comprehensive logging
- Docker Container: Isolated execution environment
- Docker Compose: Easy deployment and volume management
- JSON Configuration: Customizable package lists to monitor
- Docker and Docker Compose installed
- Read access to the directories you want to scan
- Network access for downloading container images
git clone https://github.com/Lakmal98/vulnerability-mitigation.git
cd vulnerability-mitigation
# Scan with default settings
docker compose up --build
# This will scan /opt/automation and save results to ./results/
Edit docker-compose.yaml
to change the scan directory:
volumes:
- /your/custom/path:/project:ro # Change this path
- ./packages.json:/app/packages.json:ro
- ./results:/app/results
The tool scans for packages listed in packages.json
. The current list includes known compromised packages from the September 2025 outbreak:
[
"@ctrl/tinycolor",
"@crowdstrike/logscale-parser-edit",
"@crowdstrike/logscale-file-editor",
"airpilot",
// ... more packages
]
To update the package list:
- Edit
packages.json
- Add/remove package names as needed
- Rebuild and run:
docker compose up --build
# Custom result file location
docker compose run node-modules-checker /project /app/packages.json \
--output /app/results/custom-scan.json \
--log /app/results/custom-scan.log
# Enable debug logging for detailed output
docker compose run node-modules-checker /project /app/packages.json --log-level DEBUG
# Available levels: DEBUG, INFO, WARNING, ERROR
# One-time scan of different directory
docker compose run -v /different/path:/scan:ro node-modules-checker \
/scan /app/packages.json
The tool generates two main outputs in the ./results/
directory:
{
"/path/to/project/node_modules": [
"@ctrl/tinycolor",
"airpilot"
],
"/another/project/node_modules": [
"@crowdstrike/logscale-parser-edit"
]
}
2025-09-19 10:30:15,123 - INFO - === Package Search Started ===
2025-09-19 10:30:15,124 - INFO - Base directory: /project
2025-09-19 10:30:15,124 - INFO - Looking for packages: @ctrl/tinycolor, airpilot, ...
2025-09-19 10:30:15,200 - INFO - Found package '@ctrl/tinycolor' in: /project/app1/node_modules
2025-09-19 10:30:15,300 - INFO - Search completed. Found 3 total packages in 2 directories
- Empty results.json: No compromised packages found ✅
- Populated results.json: IMMEDIATE ACTION REQUIRED
⚠️ - Contains paths to directories with potentially compromised packages
- Each entry shows the exact packages found in each location
-
Isolate affected systems - Disconnect from network if possible
-
Check for indicators of compromise:
- Search logs for webhook URL:
webhook.site/bb8ca5f6-4175-45d2-b042-fc9ebb8170b7
- Look for unexpected GitHub repositories named
Shai-Hulud
- Check for suspicious workflow files in
.github/workflows/
- Search logs for webhook URL:
-
Audit credentials:
- Rotate npm tokens
- Rotate GitHub personal access tokens
- Check AWS/GCP credentials
- Review environment variables
-
Clean infected packages:
- Delete compromised node_modules directories
- Clear npm caches:
npm cache clean --force
- Reinstall packages from known-good versions
- Check installation dates: Verify when packages were installed
- Review package-lock.json: Look for suspicious version updates after Sep 15, 2025
- Monitor system activity: Check for unusual network connections
- Scan for bundle.js files:
find . -name "bundle.js" -size +3M
- Use lockfiles: Pin to known-good versions
- Enable npm security features: Use
npm audit
- Implement cooldown periods: Delay adoption of new package versions
- Monitor continuously: Regular scans with updated package lists
# Create a script to scan multiple directories
#!/bin/bash
PROJECTS=("/opt/project1" "/opt/project2" "/opt/project3")
for project in "${PROJECTS[@]}"; do
echo "Scanning $project..."
docker compose run \
-v "$project:/scan:ro" \
-v "./results/$(basename $project):/app/results" \
node-modules-checker /scan /app/packages.json \
--output "/app/results/$(basename $project)-results.json" \
--log "/app/results/$(basename $project)-scan.log"
done
# GitHub Actions example
name: Security Scan
on: [push, pull_request]
jobs:
vulnerability-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Vulnerability Scanner
run: |
git clone https://github.com/Lakmal98/vulnerability-mitigation.git scanner
cd scanner
docker compose run \
-v "${{ github.workspace }}:/project:ro" \
node-modules-checker /project /app/packages.json
- name: Upload Results
uses: actions/upload-artifact@v4
with:
name: vulnerability-scan-results
path: scanner/results/
Create environment-specific package lists:
# Scan for CrowdStrike packages only
echo '["@crowdstrike/logscale-parser-edit", "@crowdstrike/logscale-file-editor"]' > crowdstrike-packages.json
docker compose run \
-v ./crowdstrike-packages.json:/app/packages.json:ro \
node-modules-checker /project /app/packages.json
vulnerability-mitigation/
├── find_node_modules_packages.py # Main scanner script
├── packages.json # List of packages to scan for
├── Dockerfile # Container definition
├── docker-compose.yaml # Service orchestration
├── results/ # Output directory
│ ├── results.json # Scan results
│ └── search.log # Activity log
└── README.md # This file
# Install Python dependencies (none required for basic functionality)
python3 -m venv venv
source venv/bin/activate
# Run scanner directly
python find_node_modules_packages.py /path/to/scan packages.json \
--output results.json \
--log scan.log \
--log-level DEBUG
The core scanner (find_node_modules_packages.py
) supports:
- Custom search logic: Modify the
find_packages()
function - Additional output formats: Extend the results processing
- Enhanced logging: Customize log formats and levels
- Integration hooks: Add callbacks for found packages
# Build with custom tag
docker build -t my-vulnerability-scanner .
# Use in compose
docker compose run my-vulnerability-scanner /project /app/packages.json
# Monitor for new findings
tail -f results/search.log | grep "Found package"
# Count total vulnerabilities found
grep -c "Found package" results/search.log
# Extract unique vulnerable directories
grep "Found package" results/search.log | awk '{print $NF}' | sort -u
# Simple email alert on findings
#!/bin/bash
docker compose up --build
if [ -s results/results.json ] && [ "$(cat results/results.json)" != "{}" ]; then
echo "ALERT: Vulnerable packages detected!" | mail -s "Security Alert" admin@company.com
fi
Permission Denied
# Fix volume mount permissions
chmod -R 755 /path/to/scan
sudo docker compose up --build
No Results Found
- Verify the scan path contains node_modules directories
- Check that packages.json contains valid package names
- Enable DEBUG logging to see detailed scan progress
Container Build Fails
# Clean Docker cache
docker system prune -a
docker compose build --no-cache
Large Log Files
# Rotate logs
mv results/search.log results/search-$(date +%Y%m%d).log
- Check the logs: Always start with
results/search.log
- Enable debug mode: Use
--log-level DEBUG
for detailed output - Verify inputs: Ensure scan paths and package lists are correct
- Test with known data: Run against a directory with test packages
- Read-only mounts: Scanner cannot modify scanned directories
- Isolated execution: Runs in containerized environment
- No network access: Scanner doesn't need internet connectivity
- Minimal attack surface: Simple Python script with no external dependencies
- Local execution: No data sent to external services
- Configurable output: You control where results are stored
- Audit trail: Complete logging of scanner activity
This project is released under the MIT License. See LICENSE file for details.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Submit a pull request
If you discover security issues:
- DO NOT create public issues
- Email security concerns to [maintainer email]
- Include detailed reproduction steps
- Endor Labs - npm Malware Outbreak Report
- npm Security Best Practices
- OWASP Supply Chain Security
- Docker Security Best Practices
- v1.0.0 - Initial release with basic scanning functionality
- v1.1.0 - Added comprehensive logging and Docker support
- v1.2.0 - Enhanced with malware outbreak detection capabilities
🔄 Stay Updated: Monitor security advisories and update your package lists regularly. Consider subscribing to npm security notifications and following security research organizations.