mirror of
https://github.com/prompt-security/clawsec.git
synced 2026-06-13 05:28:02 +03:00
1e48a955cc
* fix(release): exclude tests from skill payloads * fix(release): normalize test path filtering * fix(release): prefer GitHub artifacts for non-OpenClaw installs * fix(release): keep legacy ClawHub publishing * fix(release): address skill packaging review feedback * chore(skills): bump release versions * feat(skills): surface recommended platforms * docs(skills): add signed release verification * fix(skills): normalize PR version bumps --------- Co-authored-by: David Abutbul <David.a@prompt.security>
498 lines
16 KiB
Markdown
498 lines
16 KiB
Markdown
---
|
|
name: clawsec-scanner
|
|
version: 0.0.3
|
|
description: Automated vulnerability scanner for agent platforms. Performs dependency scanning (npm audit, pip-audit), multi-database CVE lookup (OSV, NVD, GitHub Advisory), SAST analysis (Semgrep, Bandit), and agent-specific DAST hook execution testing for OpenClaw hooks.
|
|
homepage: https://clawsec.prompt.security
|
|
clawdis:
|
|
emoji: "🔍"
|
|
requires:
|
|
bins: [node, npm, python3, pip-audit, semgrep, bandit, jq, curl]
|
|
---
|
|
|
|
# ClawSec Scanner
|
|
|
|
Comprehensive security scanner for agent platforms that automates vulnerability detection across multiple dimensions:
|
|
|
|
- **Dependency Scanning**: Analyzes npm and Python dependencies using `npm audit` and `pip-audit` with structured JSON output parsing
|
|
- **CVE Database Integration**: Queries OSV (primary), NVD 2.0, and GitHub Advisory Database for vulnerability enrichment
|
|
- **SAST Analysis**: Static code analysis using Semgrep (JavaScript/TypeScript) and Bandit (Python) to detect hardcoded secrets, command injection, path traversal, and unsafe deserialization
|
|
- **DAST Framework**: Agent-specific dynamic analysis with real OpenClaw hook execution harness (malicious input, timeout, output bounds, event mutation safety)
|
|
- **Unified Reporting**: Consolidated vulnerability reports with severity classification and remediation guidance
|
|
- **Continuous Monitoring**: OpenClaw hook integration for automated periodic scanning
|
|
|
|
## Features
|
|
|
|
### Multi-Engine Scanning
|
|
|
|
The scanner orchestrates four complementary scan types to provide comprehensive vulnerability coverage:
|
|
|
|
1. **Dependency Scanning**
|
|
- Executes `npm audit --json` and `pip-audit -f json` as subprocesses
|
|
- Parses structured output to extract CVE IDs, severity, affected versions
|
|
- Handles edge cases: missing package-lock.json, zero vulnerabilities, malformed JSON
|
|
|
|
2. **CVE Database Queries**
|
|
- **OSV API** (primary): Free, no authentication, broad ecosystem support (npm, PyPI, Go, Maven)
|
|
- **NVD 2.0** (optional): Requires API key to avoid 6-second rate limiting
|
|
- **GitHub Advisory Database** (optional): GraphQL API with OAuth token
|
|
- Normalizes all API responses to unified `Vulnerability` schema
|
|
|
|
3. **Static Analysis (SAST)**
|
|
- **Semgrep** for JavaScript/TypeScript: Detects security issues using `--config auto` or `--config p/security-audit`
|
|
- **Bandit** for Python: Leverages existing `pyproject.toml` configuration
|
|
- Identifies: hardcoded secrets (API keys, tokens), command injection (`eval`, `exec`), path traversal, unsafe deserialization
|
|
|
|
4. **Dynamic Analysis (DAST)**
|
|
- Real hook execution harness for OpenClaw hook handlers discovered from `HOOK.md` metadata
|
|
- Verifies: malicious input resilience, timeout behavior, output amplification bounds, and core event mutation safety
|
|
- Note: Traditional web DAST tools (ZAP, Burp) do not apply to agent platforms - this provides agent-specific testing
|
|
|
|
### Unified Reporting
|
|
|
|
All scan types emit a consistent `ScanReport` JSON schema:
|
|
|
|
```typescript
|
|
{
|
|
scan_id: string; // UUID
|
|
timestamp: string; // ISO 8601
|
|
target: string; // Scanned path
|
|
vulnerabilities: Vulnerability[];
|
|
summary: {
|
|
critical: number;
|
|
high: number;
|
|
medium: number;
|
|
low: number;
|
|
info: number;
|
|
}
|
|
}
|
|
```
|
|
|
|
Each `Vulnerability` object includes:
|
|
- `id`: CVE-2023-12345 or GHSA-xxxx-yyyy-zzzz
|
|
- `source`: npm-audit | pip-audit | osv | nvd | github | sast | dast
|
|
- `severity`: critical | high | medium | low | info
|
|
- `package`: Package name (or 'N/A' for SAST/DAST)
|
|
- `version`: Affected version
|
|
- `fixed_version`: First version with fix (if available)
|
|
- `title`: Short description
|
|
- `description`: Full advisory text
|
|
- `references`: URLs for more info
|
|
- `discovered_at`: ISO 8601 timestamp
|
|
|
|
### OpenClaw Integration
|
|
|
|
Automated continuous monitoring via hook:
|
|
|
|
- Runs scanner on configurable interval (default: 86400s / 24 hours)
|
|
- Triggers on `agent:bootstrap` and `command:new` events
|
|
- Posts findings to `event.messages` array with severity summary
|
|
- Rate-limited by `CLAWSEC_SCANNER_INTERVAL` environment variable
|
|
|
|
## Installation
|
|
|
|
### Prerequisites
|
|
|
|
Verify required binaries are available:
|
|
|
|
```bash
|
|
# Core runtimes
|
|
node --version # v20+
|
|
npm --version
|
|
python3 --version # 3.10+
|
|
|
|
# Scanning tools
|
|
pip-audit --version # Install: uv pip install pip-audit
|
|
semgrep --version # Install: pip install semgrep OR brew install semgrep
|
|
bandit --version # Install: uv pip install bandit
|
|
|
|
# Utilities
|
|
jq --version
|
|
curl --version
|
|
```
|
|
|
|
### Option A: Via clawhub (recommended)
|
|
|
|
```bash
|
|
npx clawhub@latest install clawsec-scanner
|
|
```
|
|
|
|
### Option B: Manual installation with verification
|
|
|
|
```bash
|
|
set -euo pipefail
|
|
|
|
VERSION="${SKILL_VERSION:?Set SKILL_VERSION (e.g. 0.1.0)}"
|
|
INSTALL_ROOT="${INSTALL_ROOT:-$HOME/.openclaw/skills}"
|
|
DEST="$INSTALL_ROOT/clawsec-scanner"
|
|
BASE="https://github.com/prompt-security/clawsec/releases/download/clawsec-scanner-v${VERSION}"
|
|
|
|
TEMP_DIR="$(mktemp -d)"
|
|
trap 'rm -rf "$TEMP_DIR"' EXIT
|
|
|
|
# Pinned release-signing public key
|
|
# Fingerprint (SHA-256 of SPKI DER): 711424e4535f84093fefb024cd1ca4ec87439e53907b305b79a631d5befba9c8
|
|
cat > "$TEMP_DIR/release-signing-public.pem" <<'PEM'
|
|
-----BEGIN PUBLIC KEY-----
|
|
MCowBQYDK2VwAyEAS7nijfMcUoOBCj4yOXJX+GYGv2pFl2Yaha1P4v5Cm6A=
|
|
-----END PUBLIC KEY-----
|
|
PEM
|
|
|
|
ZIP_NAME="clawsec-scanner-v${VERSION}.zip"
|
|
|
|
# Download release archive + signed checksums
|
|
curl -fsSL "$BASE/$ZIP_NAME" -o "$TEMP_DIR/$ZIP_NAME"
|
|
curl -fsSL "$BASE/checksums.json" -o "$TEMP_DIR/checksums.json"
|
|
curl -fsSL "$BASE/checksums.sig" -o "$TEMP_DIR/checksums.sig"
|
|
|
|
# Verify checksums manifest signature
|
|
openssl base64 -d -A -in "$TEMP_DIR/checksums.sig" -out "$TEMP_DIR/checksums.sig.bin"
|
|
if ! openssl pkeyutl -verify \
|
|
-pubin \
|
|
-inkey "$TEMP_DIR/release-signing-public.pem" \
|
|
-sigfile "$TEMP_DIR/checksums.sig.bin" \
|
|
-rawin \
|
|
-in "$TEMP_DIR/checksums.json" >/dev/null 2>&1; then
|
|
echo "ERROR: checksums.json signature verification failed" >&2
|
|
exit 1
|
|
fi
|
|
|
|
EXPECTED_SHA="$(jq -r '.archive.sha256 // empty' "$TEMP_DIR/checksums.json")"
|
|
if [ -z "$EXPECTED_SHA" ]; then
|
|
echo "ERROR: checksums.json missing archive.sha256" >&2
|
|
exit 1
|
|
fi
|
|
|
|
ACTUAL_SHA="$(shasum -a 256 "$TEMP_DIR/$ZIP_NAME" | awk '{print $1}')"
|
|
if [ "$EXPECTED_SHA" != "$ACTUAL_SHA" ]; then
|
|
echo "ERROR: Archive checksum mismatch" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Checksums verified. Installing..."
|
|
|
|
mkdir -p "$INSTALL_ROOT"
|
|
rm -rf "$DEST"
|
|
unzip -q "$TEMP_DIR/$ZIP_NAME" -d "$INSTALL_ROOT"
|
|
|
|
chmod 600 "$DEST/skill.json"
|
|
find "$DEST" -type f ! -name "skill.json" -exec chmod 644 {} \;
|
|
|
|
echo "Installed clawsec-scanner v${VERSION} to: $DEST"
|
|
echo "Next step: Run a scan or set up continuous monitoring"
|
|
```
|
|
|
|
## Usage
|
|
|
|
### On-Demand CLI Scanning
|
|
|
|
```bash
|
|
SCANNER_DIR="${INSTALL_ROOT:-$HOME/.openclaw/skills}/clawsec-scanner"
|
|
|
|
# Scan all skills with JSON output
|
|
"$SCANNER_DIR/scripts/runner.sh" --target ./skills/ --output report.json --format json
|
|
|
|
# Scan specific directory with human-readable output
|
|
"$SCANNER_DIR/scripts/runner.sh" --target ./my-skill/ --format text
|
|
|
|
# Check available flags
|
|
"$SCANNER_DIR/scripts/runner.sh" --help
|
|
```
|
|
|
|
**CLI Flags:**
|
|
- `--target <path>`: Directory to scan (required)
|
|
- `--output <file>`: Write results to file (optional, defaults to stdout)
|
|
- `--format <json|text>`: Output format (default: json)
|
|
- `--check`: Verify all required binaries are installed
|
|
|
|
### OpenClaw Hook Setup (Continuous Monitoring)
|
|
|
|
Enable automated periodic scanning:
|
|
|
|
```bash
|
|
SCANNER_DIR="${INSTALL_ROOT:-$HOME/.openclaw/skills}/clawsec-scanner"
|
|
node "$SCANNER_DIR/scripts/setup_scanner_hook.mjs"
|
|
```
|
|
|
|
This creates a hook that:
|
|
- Scans on `agent:bootstrap` and `command:new` events
|
|
- Respects `CLAWSEC_SCANNER_INTERVAL` rate limiting (default: 86400 seconds / 24 hours)
|
|
- Posts findings to conversation with severity summary
|
|
- Recommends remediation for high/critical vulnerabilities
|
|
|
|
Restart the OpenClaw gateway after enabling the hook, then run `/new` to trigger an immediate scan.
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Optional - NVD API key to avoid rate limiting (6-second delays without key)
|
|
export CLAWSEC_NVD_API_KEY="your-nvd-api-key"
|
|
|
|
# Optional - GitHub OAuth token for Advisory Database queries
|
|
export GITHUB_TOKEN="ghp_your_token_here"
|
|
|
|
# Optional - Scanner hook interval in seconds (default: 86400 / 24 hours)
|
|
export CLAWSEC_SCANNER_INTERVAL="86400"
|
|
|
|
# Optional - Allow unsigned advisory feed during development (from clawsec-suite)
|
|
export CLAWSEC_ALLOW_UNSIGNED_FEED="1"
|
|
```
|
|
|
|
## Architecture
|
|
|
|
### Modular Design
|
|
|
|
Each scan type is an independent module that can run standalone or as part of unified scan:
|
|
|
|
```
|
|
scripts/runner.sh # Orchestration layer
|
|
├── scan_dependencies.mjs # npm audit + pip-audit
|
|
├── query_cve_databases.mjs # OSV/NVD/GitHub API queries
|
|
├── sast_analyzer.mjs # Semgrep + Bandit static analysis
|
|
├── dast_runner.mjs # Dynamic security testing orchestration
|
|
└── dast_hook_executor.mjs # Isolated real hook execution harness
|
|
|
|
lib/
|
|
├── report.mjs # Result aggregation and formatting
|
|
├── utils.mjs # Subprocess exec, JSON parsing, error handling
|
|
└── types.ts # TypeScript schema definitions
|
|
|
|
hooks/clawsec-scanner-hook/
|
|
├── HOOK.md # OpenClaw hook metadata
|
|
└── handler.ts # Periodic scan trigger
|
|
```
|
|
|
|
### Fail-Open Philosophy
|
|
|
|
The scanner prioritizes availability over strict failure propagation:
|
|
|
|
- Network failures → emit partial results, log warnings
|
|
- Missing tools → skip that scan type, continue with others
|
|
- Malformed JSON → parse what's valid, log errors
|
|
- API rate limits → implement exponential backoff, fallback to other sources
|
|
- Zero vulnerabilities → emit success report with empty array
|
|
|
|
**Critical failures** that exit immediately:
|
|
- Target path does not exist
|
|
- No scanning tools available (all bins missing)
|
|
- Concurrent scan detected (lockfile present)
|
|
|
|
### Subprocess Execution Pattern
|
|
|
|
All external tools run as subprocesses with structured JSON output:
|
|
|
|
```javascript
|
|
import { spawn } from 'node:child_process';
|
|
|
|
// Example: npm audit execution
|
|
const proc = spawn('npm', ['audit', '--json'], {
|
|
cwd: targetPath,
|
|
stdio: ['ignore', 'pipe', 'pipe']
|
|
});
|
|
|
|
// Handle non-zero exit codes gracefully
|
|
// npm audit exits 1 when vulnerabilities found (not an error!)
|
|
proc.on('close', code => {
|
|
if (code !== 0 && stderr.includes('ERR!')) {
|
|
// Actual error
|
|
reject(new Error(stderr));
|
|
} else {
|
|
// Vulnerabilities found or success
|
|
resolve(JSON.parse(stdout));
|
|
}
|
|
});
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
**"Missing package-lock.json" warning**
|
|
- `npm audit` requires lockfile to run
|
|
- Run `npm install` in target directory to generate
|
|
- Scanner continues with other scan types if npm audit fails
|
|
|
|
**"NVD API rate limit exceeded"**
|
|
- Set `CLAWSEC_NVD_API_KEY` environment variable
|
|
- Without API key: 6-second delays enforced between requests
|
|
- OSV API used as primary source (no rate limits)
|
|
|
|
**"pip-audit not found"**
|
|
- Install: `uv pip install pip-audit` or `pip install pip-audit`
|
|
- Verify: `which pip-audit`
|
|
- Add to PATH if installed in non-standard location
|
|
|
|
**"Semgrep binary missing"**
|
|
- Install: `pip install semgrep` OR `brew install semgrep`
|
|
- Requires Python 3.8+ runtime
|
|
- Alternative: use Docker image `returntocorp/semgrep`
|
|
|
|
**"TypeScript hook not executable in DAST harness"**
|
|
- The DAST harness executes real hook handlers and transpiles `handler.ts` files when a TypeScript compiler is available
|
|
- Install TypeScript in the scanner environment: `npm install -D typescript` (or provide `handler.js`/`handler.mjs`)
|
|
- Without a compiler, scanner reports an `info`-level coverage finding instead of a high-severity vulnerability
|
|
|
|
**"Concurrent scan detected"**
|
|
- Lockfile exists: `/tmp/clawsec-scanner.lock`
|
|
- Wait for running scan to complete or manually remove lockfile
|
|
- Prevents overlapping scans that could produce inconsistent results
|
|
|
|
### Verification
|
|
|
|
Check scanner is working correctly:
|
|
|
|
```bash
|
|
# Verify required binaries
|
|
./scripts/runner.sh --check
|
|
|
|
# Run unit tests
|
|
node test/dependency_scanner.test.mjs
|
|
node test/cve_integration.test.mjs
|
|
node test/sast_engine.test.mjs
|
|
node test/dast_harness.test.mjs
|
|
|
|
# Validate skill structure
|
|
python ../../utils/validate_skill.py .
|
|
|
|
# Scan test fixtures (should detect known vulnerabilities)
|
|
./scripts/runner.sh --target test/fixtures/ --format text
|
|
```
|
|
|
|
## Development
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
# All tests (vanilla Node.js, no framework)
|
|
for test in test/*.test.mjs; do
|
|
node "$test" || exit 1
|
|
done
|
|
|
|
# Individual test suites
|
|
node test/dependency_scanner.test.mjs # Dependency scanning
|
|
node test/cve_integration.test.mjs # CVE database APIs
|
|
node test/sast_engine.test.mjs # Static analysis
|
|
node test/dast_harness.test.mjs # DAST harness execution
|
|
```
|
|
|
|
### Linting
|
|
|
|
```bash
|
|
# JavaScript/TypeScript
|
|
npx eslint . --ext .ts,.tsx,.js,.jsx,.mjs --max-warnings 0
|
|
|
|
# Python (Bandit already configured in pyproject.toml)
|
|
ruff check .
|
|
bandit -r . -ll
|
|
|
|
# Shell scripts
|
|
shellcheck scripts/*.sh
|
|
```
|
|
|
|
### Adding Custom Semgrep Rules
|
|
|
|
Create custom rules in `.semgrep/rules/`:
|
|
|
|
```yaml
|
|
rules:
|
|
- id: custom-security-rule
|
|
pattern: dangerous_function($ARG)
|
|
message: Avoid dangerous_function - use safe_alternative instead
|
|
severity: WARNING
|
|
languages: [javascript, typescript]
|
|
```
|
|
|
|
Update `scripts/sast_analyzer.mjs` to include custom rules:
|
|
|
|
```javascript
|
|
const proc = spawn('semgrep', [
|
|
'scan',
|
|
'--config', 'auto',
|
|
'--config', '.semgrep/rules/', // Add custom rules
|
|
'--json',
|
|
targetPath
|
|
]);
|
|
```
|
|
|
|
## Integration with ClawSec Suite
|
|
|
|
The scanner works standalone or as part of the ClawSec ecosystem:
|
|
|
|
- **clawsec-suite**: Meta-skill that can install and manage clawsec-scanner
|
|
- **clawsec-feed**: Advisory feed for malicious skill detection (complementary)
|
|
- **openclaw-audit-watchdog**: Cron-based audit automation (similar pattern)
|
|
|
|
Install the full ClawSec suite:
|
|
|
|
```bash
|
|
npx clawhub@latest install clawsec-suite
|
|
# Then use clawsec-suite to discover and install clawsec-scanner
|
|
```
|
|
|
|
## Security Considerations
|
|
|
|
### Scanner Security
|
|
|
|
- No hardcoded secrets in scanner code
|
|
- API keys read from environment variables only (never logged or committed)
|
|
- Subprocess arguments use arrays to prevent shell injection
|
|
- All external tool output parsed with try/catch error handling
|
|
|
|
### Vulnerability Prioritization
|
|
|
|
**Critical/High severity findings** should be addressed immediately:
|
|
- Known exploits in dependencies (CVSS 9.0+)
|
|
- Hardcoded API keys or credentials in code
|
|
- Command injection vulnerabilities
|
|
- Path traversal without validation
|
|
|
|
**Medium/Low severity findings** can be addressed in normal sprint cycles:
|
|
- Outdated dependencies without known exploits
|
|
- Missing security headers
|
|
- Weak cryptography usage
|
|
|
|
**Info findings** are advisory only:
|
|
- Deprecated API usage
|
|
- Code quality issues flagged by linters
|
|
|
|
## Roadmap
|
|
|
|
### v0.0.2 (Current)
|
|
- [x] Dependency scanning (npm audit, pip-audit)
|
|
- [x] CVE database integration (OSV, NVD, GitHub Advisory)
|
|
- [x] SAST analysis (Semgrep, Bandit)
|
|
- [x] Real OpenClaw hook execution harness for DAST
|
|
- [x] Unified JSON reporting
|
|
- [x] OpenClaw hook integration
|
|
|
|
### Future Enhancements
|
|
- [ ] Automatic remediation (dependency upgrades, code fixes)
|
|
- [ ] SARIF output format for GitHub Code Scanning integration
|
|
- [ ] Web dashboard for vulnerability tracking over time
|
|
- [ ] CI/CD GitHub Action for PR blocking on high-severity findings
|
|
- [ ] Container image scanning (Docker, OCI)
|
|
- [ ] Infrastructure-as-Code scanning (Terraform, CloudFormation)
|
|
- [ ] Comprehensive agent workflow DAST (requires deeper platform integration)
|
|
|
|
## Contributing
|
|
|
|
Found a security issue? Please report privately to security@prompt.security.
|
|
|
|
For feature requests and bug reports, open an issue at:
|
|
https://github.com/prompt-security/clawsec/issues
|
|
|
|
## License
|
|
|
|
AGPL-3.0-or-later
|
|
|
|
See LICENSE file in repository root for full text.
|
|
|
|
## Resources
|
|
|
|
- **ClawSec Homepage**: https://clawsec.prompt.security
|
|
- **Documentation**: https://clawsec.prompt.security/scanner
|
|
- **GitHub Repository**: https://github.com/prompt-security/clawsec
|
|
- **OSV API Docs**: https://osv.dev/docs/
|
|
- **NVD API Docs**: https://nvd.nist.gov/developers/vulnerabilities
|
|
- **Semgrep Registry**: https://semgrep.dev/explore
|
|
- **Bandit Documentation**: https://bandit.readthedocs.io/
|