CLI
Developer-first command line interface for scans, batch runs, and live monitoring.
Malware Scanner CLI
A command-line tool for scanning npm packages for malicious code patterns, typosquatting, and security vulnerabilities.
Installation
# Install globally
npm install -g malwarescanner
# Or run directly with bun
bun run src/cli/scanner.ts
Quick Start
# Scan a package from npm
malware-scanner scan lodash
# Scan multiple packages from a file
malware-scanner batch -f packages.txt
# Monitor npm registry in real-time
malware-scanner live
Commands
scan - Scan a single package
Scans an npm package for malware patterns, suspicious code, and security issues.
# Scan latest version from npm
malware-scanner scan lodash
# Scan specific version
malware-scanner scan lodash@4.17.21
# Scan scoped package
malware-scanner scan @types/node
# Scan local directory
malware-scanner scan --local ./my-package
# Scan local tarball
malware-scanner scan --tarball ./package.tgz
# Pipe tarball from stdin
cat package.tgz | malware-scanner scan --stdin
# Output as JSON
malware-scanner scan lodash --json
# Save results to file
malware-scanner scan lodash -o results.json --json
Options:
| Option | Description |
|---|---|
-j, --json | Output results as JSON |
-q, --quiet | Suppress progress output |
-l, --local | Scan a local directory |
-t, --tarball | Scan a local tarball file (.tgz) |
--stdin | Read tarball from stdin (max 100MB, 30s timeout) |
-o, --output <file> | Write results to file |
--timeout <seconds> | Scan timeout in seconds (default: 300) |
Exit Codes:
0- Package is clean1- Warnings detected or scan error2- Critical threats detected
batch - Scan multiple packages
Scans multiple packages from a file or stdin with concurrency control and rate limiting.
# Scan packages from file
malware-scanner batch -f packages.txt
# Scan from stdin
echo -e "lodash\nreact\nexpress" | malware-scanner batch
# Save results to JSON file
malware-scanner batch -f packages.txt -o results.json
# Output as streaming NDJSON
malware-scanner batch -f packages.txt --json
# Adjust concurrency (default: 3, max: 10)
malware-scanner batch -f packages.txt -c 5
# Stop on first critical threat
malware-scanner batch -f packages.txt --fail-fast
Package File Format:
# Comments start with hash
lodash@4.17.21
@types/node
react
express@^4.18.0
Options:
| Option | Description |
|---|---|
-f, --file <path> | Input file with package list (one per line) |
-o, --output <path> | Output file for results (JSON format) |
-j, --json | Output results as NDJSON to stdout |
-q, --quiet | Suppress progress output |
-c, --concurrency <n> | Number of concurrent scans (1-10, default: 3) |
--fail-fast | Stop on first critical threat |
--timeout <seconds> | Scan timeout per package (default: 300) |
Rate Limiting: The batch command includes automatic rate limiting:
- 100ms delay between batches
- Exponential backoff on 429 errors (1s → 2s → 4s → ... up to 30s)
- Up to 3 retries per package on rate limit errors
live - Monitor npm registry
Monitors the npm registry changes feed in real-time and scans new package publications.
# Start monitoring with defaults
malware-scanner live
# Only report critical threats
malware-scanner live -t critical
# Output as JSON events (for piping to other tools)
malware-scanner live --json
# Skip scoped packages
malware-scanner live --skip-scoped
# Adjust queue depth for backpressure control
malware-scanner live -m 500
Options:
| Option | Description |
|---|---|
-t, --threshold <level> | Minimum threat level to report (info|warning|critical) |
-m, --max-queue <n> | Maximum queue depth before backpressure (default: 1000) |
-s, --skip-scoped | Skip scoped packages (@org/name) |
-j, --json | Output events as JSON (one per line) |
-q, --quiet | Suppress all output except threats |
Requirements:
- Redis server running on localhost:6379 (or set
REDIS_URLenv var)
Example Redis setup:
docker run -d -p 6379:6379 redis
config - Manage configuration
# Create a sample config file
malware-scanner config init
# Show current configuration
malware-scanner config show
# Show config as JSON
malware-scanner config show --json
# Show path to active config file
malware-scanner config path
completion - Shell completions
Generate shell completion scripts for enhanced command-line experience.
# Bash
malware-scanner completion bash >> ~/.bashrc
# Zsh
malware-scanner completion zsh >> ~/.zshrc
# Fish
malware-scanner completion fish > ~/.config/fish/completions/malware-scanner.fish
Configuration
The CLI supports multiple configuration sources (in order of precedence):
- CLI arguments (highest priority)
- Environment variables
- Configuration files
- Defaults (lowest priority)
Configuration Files
Create a configuration file in any of these formats:
.malwarescannerrc.json.malwarescannerrc.yaml/.malwarescannerrc.yml.malwarescannerrc.js/.malwarescannerrc.cjs/.malwarescannerrc.mjsmalwarescanner.config.jspackage.json(under"malwarescanner"key)
Example .malwarescannerrc.json:
{
"threshold": "warning",
"format": "console",
"timeout": 300,
"concurrency": 3,
"maxQueueDepth": 1000,
"skipScoped": false,
"plugins": {
"installScripts": true,
"networkAccess": true,
"typosquat": true,
"obfuscation": true,
"llmAnalysis": false
},
"thresholds": {
"obfuscationEntropy": 5.5,
"typosquatLevenshtein": 2
}
}
Environment Variables
| Variable | Description |
|---|---|
MALWARE_SCANNER_THRESHOLD | Default threat level threshold (info|warning|critical) |
MALWARE_SCANNER_FORMAT | Output format (console|json) |
MALWARE_SCANNER_TIMEOUT | Default timeout in seconds |
MALWARE_SCANNER_CONCURRENCY | Default concurrency (1-10) |
REDIS_URL | Redis connection URL for live monitoring |
ANTHROPIC_API_KEY | API key for LLM-based analysis |
NO_COLOR | Disable colored output (any value) |
FORCE_COLOR | Force color level (0-3) |
Global Options
These options work with all commands:
| Option | Description |
|---|---|
--no-color | Disable colored output |
--verbose | Enable verbose output for debugging |
-h, --help | Show help |
-V, --version | Show version |
Output Formats
Console (Default)
Human-readable colored output with threat indicators:
Scan Results: lodash@4.17.21
──────────────────────────────────────────────────
✓ No issues detected
Threat Level: CLEAN
Threat Score: 0/100
Scan Duration: 1234ms
JSON
Structured output for automation:
malware-scanner scan lodash --json
{
"packageName": "lodash",
"version": "4.17.21",
"threatLevel": "clean",
"threatScore": 0,
"alerts": [],
"scanDurationMs": 1234,
"scannedAt": "2024-01-15T10:30:00.000Z"
}
NDJSON (Batch)
Newline-delimited JSON for streaming:
malware-scanner batch -f packages.txt --json
{"type":"scan_result","packageSpec":"lodash@4.17.21","threatLevel":"clean",...}
{"type":"scan_result","packageSpec":"react@18.2.0","threatLevel":"clean",...}
{"type":"scan_error","packageSpec":"nonexistent-pkg","error":"Package not found"}
Detection Capabilities
The scanner checks for:
- Install Scripts: Suspicious
preinstall,postinstall,preparehooks - Network Access: Code that makes HTTP/HTTPS requests, DNS lookups, or socket connections
- Typosquatting: Package names similar to popular packages (Levenshtein distance, keyboard proximity)
- Obfuscation: High entropy code, base64-encoded payloads, eval usage
- Sensitive File Access: Attempts to read
.npmrc,.ssh, credentials, etc. - Environment Access: Code accessing sensitive environment variables
- Child Process: Spawning shells or executing commands
Examples
CI/CD Integration
# GitHub Actions example
- name: Scan dependencies
run: |
npm install -g malwarescanner
malware-scanner batch -f package-lock.json --fail-fast
if [ $? -eq 2 ]; then
echo "Critical threats detected!"
exit 1
fi
Scripting with JSON
# Get threat level programmatically
threat_level=$(malware-scanner scan lodash --json | jq -r '.threatLevel')
if [ "$threat_level" = "critical" ]; then
echo "Do not install this package!"
fi
Verbose Debugging
# See detailed scan progress
malware-scanner scan lodash --verbose
Output:
[verbose] Loading configuration...
[verbose] Config loaded: timeout=300s, threshold=warning
[verbose] Creating detection service with timeout: 300s
[verbose] Scanning npm package: lodash@latest
[verbose] Fetching package from npm registry...
[verbose] Scan complete: 0 alerts, threat level: clean, duration: 1234ms
[verbose] Output written to stdout
Troubleshooting
"No data piped to stdin"
When using --stdin, make sure to pipe data:
cat package.tgz | malware-scanner scan --stdin
"Redis connection refused" (live command)
Start Redis before using the live monitor:
docker run -d -p 6379:6379 redis
# or
brew services start redis
Rate limiting in batch mode
The batch command handles rate limiting automatically. If you see many retries, consider:
- Reducing concurrency:
-c 1 - Adding delays between runs
- Using a caching npm registry proxy
Large packages timing out
Increase the timeout:
malware-scanner scan large-package --timeout 600
License
MIT