Files
davila7__claude-code-templates/cli-tool/components/hooks/security/dangerous-command-blocker.py
Daniel Avila ceb3a9e40c feat(hooks): enhance dangerous-command-blocker with multi-level security (#281)
Enhanced the dangerous-command-blocker hook with comprehensive protection:

## Features:
- **3-Level Security System:**
  - Level 1: Block catastrophic commands (rm -rf /, dd, mkfs, fork bombs)
  - Level 2: Protect critical paths (.claude/, .git/, node_modules/, .env, etc.)
  - Level 3: Warn about suspicious patterns (wildcards, chained commands)

- **Python Script Architecture:**
  - Moved from inline Python to dedicated script for better maintainability
  - Script auto-installed to .claude/scripts/dangerous-command-blocker.py
  - Clear regex patterns and detailed error messages

- **Protected Resources:**
  - Claude Code configuration (.claude/)
  - Git repository (.git/)
  - Node.js dependencies (node_modules/, package.json, package-lock.json)
  - Environment files (.env, .env.local, etc.)
  - Language manifests (Cargo.toml, go.mod, requirements.txt, Gemfile, composer.json)

## Testing:
- 16/16 test cases passing (100%)
- Blocks catastrophic operations
- Protects critical project files
- Warns on suspicious patterns
- Allows safe operations

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-17 23:10:35 -05:00

99 lines
4.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Dangerous Command Blocker Hook
Multi-level security system for blocking dangerous shell commands
"""
import json
import sys
import re
# Load command from stdin
data = json.load(sys.stdin)
cmd = data.get('tool_input', {}).get('command', '')
# === LEVEL 1: CATASTROPHIC COMMANDS (ALWAYS BLOCK) ===
catastrophic_patterns = [
(r'\brm\s+.*\s+/\s*$', 'rm on root directory'),
(r'\brm\s+.*\s+~\s*$', 'rm on home directory'),
(r'\brm\s+.*\s+\*\s*$', 'rm with star wildcard'),
(r'\brm\s+-[rfRF]*[rfRF]+.*\*', 'rm -rf with wildcards'),
(r'\b(dd\s+if=|dd\s+of=/dev)', 'dd disk operations'),
(r'\b(mkfs\.|mkswap\s|fdisk\s)', 'filesystem formatting'),
(r'\b:(\(\))?\s*\{\s*:\s*\|\s*:\s*&\s*\}', 'fork bomb'),
(r'>\s*/dev/sd[a-z]', 'direct disk write'),
(r'\bchmod\s+(-R\s+)?777\s+/', 'chmod 777 on root'),
(r'\bchown\s+(-R\s+)?.*\s+/$', 'chown on root directory'),
]
for pattern, desc in catastrophic_patterns:
if re.search(pattern, cmd, re.IGNORECASE):
print(f'❌ BLOCKED: Catastrophic command detected!', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'Reason: {desc}', file=sys.stderr)
print(f'Command: {cmd[:100]}', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'This command could cause IRREVERSIBLE system damage or data loss.', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'Safety tips:', file=sys.stderr)
print(f' • Never use rm -rf with /, ~, or * wildcards', file=sys.stderr)
print(f' • Avoid recursive operations on system directories', file=sys.stderr)
print(f' • Use specific file paths instead of wildcards', file=sys.stderr)
print(f' • For cleanup, target specific directories: rm -rf /tmp/myproject', file=sys.stderr)
sys.exit(2)
# === LEVEL 2: CRITICAL PATH PROTECTION ===
critical_paths = [
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?\.claude(/|$|\s)', 'Claude Code configuration'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?\.git(/|$|\s)', 'Git repository'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?node_modules(/|$|\s)', 'Node.js dependencies'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*\.env\b', 'Environment variables'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*package\.json\b', 'Package manifest'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*package-lock\.json\b', 'Lock file'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*yarn\.lock\b', 'Yarn lock file'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*Cargo\.toml\b', 'Rust manifest'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*go\.mod\b', 'Go module file'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*requirements\.txt\b', 'Python dependencies'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*Gemfile(\.lock)?\b', 'Ruby dependencies'),
(r'\b(rm|mv)\s+(-[rfRF]+\s+)?[^\s]*composer\.json\b', 'PHP dependencies'),
]
for pattern, desc in critical_paths:
if re.search(pattern, cmd, re.IGNORECASE):
print(f'🛑 BLOCKED: Critical path protection activated!', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'Protected resource: {desc}', file=sys.stderr)
print(f'Command: {cmd[:100]}', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'This path contains critical project files that should not be deleted accidentally.', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'If you really need to modify this:', file=sys.stderr)
print(f' 1. Disable the hook temporarily in .claude/hooks.json', file=sys.stderr)
print(f' 2. Execute the command manually in your terminal', file=sys.stderr)
print(f' 3. Or modify specific files instead of using rm/mv on entire directories', file=sys.stderr)
sys.exit(2)
# === LEVEL 3: SUSPICIOUS PATTERNS (WARNING) ===
suspicious_patterns = [
(r'\brm\s+.*\s+&&', 'chained rm commands'),
(r'\brm\s+[^\s/]*\*', 'rm with wildcards'),
(r'\bfind\s+.*-delete', 'find -delete operation'),
(r'\bxargs\s+.*\brm', 'xargs with rm'),
]
for pattern, desc in suspicious_patterns:
if re.search(pattern, cmd, re.IGNORECASE):
print(f'⚠️ WARNING: Suspicious command pattern detected!', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'Pattern: {desc}', file=sys.stderr)
print(f'Command: {cmd[:100]}', file=sys.stderr)
print(f'', file=sys.stderr)
print(f'This command uses patterns that could accidentally delete more than intended.', file=sys.stderr)
print(f'Consider reviewing the command carefully before execution.', file=sys.stderr)
print(f'', file=sys.stderr)
# Exit 0 to allow but with warning
sys.exit(0)
# Command is safe
sys.exit(0)