Security Hooks¶
This document details the security hooks that protect Project Aegis from dangerous operations.
Overview¶
Aegis uses Claude Code's hook system to intercept and validate operations before they execute. Hooks are configured in ~/.claude/settings.json and execute as Python or Bash scripts.
Hook Configuration¶
Location: ~/.claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "/home/agent/.claude/hooks/block-sensitive-files.py",
"timeout": 5
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/home/agent/.claude/hooks/bash-validator.py",
"timeout": 5
}
]
},
{
"matcher": "mcp__",
"hooks": [
{
"type": "command",
"command": "/home/agent/.claude/hooks/mcp-param-validator.py",
"timeout": 5
}
]
}
],
"PostToolUse": [
{
"matcher": "mcp__",
"hooks": [
{
"type": "command",
"command": "/home/agent/.claude/hooks/mcp-security-audit.py",
"timeout": 5
}
]
}
]
}
}
Hook Types¶
PreToolUse¶
Executes before a tool runs. Exit codes determine behavior:
0: Allow operation1: Non-blocking error (log and continue)2: Block operation (prevents execution)
PostToolUse¶
Executes after a tool runs. Used for logging and auditing (cannot block).
Hook Events¶
| Event | When It Fires | Use Cases |
|---|---|---|
| PreToolUse | Before tool execution | Validation, blocking dangerous operations |
| PostToolUse | After tool execution | Audit logging, cost tracking |
| SessionStart | When Claude Code starts | Load tasks, check system state |
| Stop | When Claude Code stops | Quality gates, autonomous mode |
| Notification | On system notifications | Forward alerts to Discord/Telegram |
| PermissionRequest | On permission dialogs | Auto-approve trusted operations |
Security Hooks in Detail¶
1. block-sensitive-files.py¶
Purpose: Prevent modification of credentials, secrets, and critical system files.
Hook Type: PreToolUse (Write, Edit)
Location: /home/agent/.claude/hooks/block-sensitive-files.py
Protected Patterns (BLOCK)¶
Operations on these files are blocked (exit code 2):
PROTECTED_PATTERNS = [
r'\.pem$', # SSL certificates
r'\.key$', # Private keys
r'id_rsa', # SSH RSA keys
r'id_ed25519', # SSH Ed25519 keys
r'/\.git/', # Git internals
r'package-lock\.json$', # Lock files
r'yarn\.lock$',
r'poetry\.lock$',
]
Example Blocked Operation:
Caution Patterns (WARN)¶
Operations on these files are allowed but warned:
CAUTION_PATTERNS = [
r'\.env$', # Environment files
r'\.env\.', # .env.production, etc.
r'/\.secure/', # Credentials directory
r'credentials', # Any credentials file
r'settings\.json$', # Claude settings
r'config\.json$', # Config files
r'docker-compose.*\.yml$', # Docker Compose files
r'\.claude\.json$', # MCP config
]
Example Warning:
Tool: Edit
File: ~/.secure/.env
Result: ALLOWED with warning "CAUTION: Modifying sensitive config: /home/agent/.secure/.env"
Use Cases¶
- Prevent accidental credential exposure
- Block editing of SSH keys
- Protect Git internals from corruption
- Allow intentional .env editing (with warnings)
2. bash-validator.py¶
Purpose: Block potentially destructive Bash commands.
Hook Type: PreToolUse (Bash)
Location: /home/agent/.claude/hooks/bash-validator.py
Dangerous Patterns (BLOCK)¶
DANGEROUS_PATTERNS = [
(r'\brm\s+-rf\s+/', 'rm -rf on root path'),
(r'\brm\s+-rf\s+~', 'rm -rf on home directory'),
(r'\brm\s+-rf\s+\*', 'rm -rf with wildcard'),
(r'\bsudo\s+rm\s+-rf', 'sudo rm -rf'),
(r'\bchmod\s+777', 'overly permissive chmod 777'),
(r'\bmkfs\.', 'filesystem formatting'),
(r'\bdd\s+.*of=/dev/', 'dd to device'),
(r':(){.*};:', 'fork bomb pattern'),
(r'\beval\s+.*\$', 'eval with variable expansion'),
(r'>\s*/etc/', 'redirect to /etc'),
(r'\bgit\s+push\s+.*--force\s+.*main', 'force push to main'),
(r'\bgit\s+push\s+.*--force\s+.*master', 'force push to master'),
(r'\bgit\s+reset\s+--hard\s+origin', 'hard reset to origin'),
]
Example Blocked Operations:
# Blocked
rm -rf /var/log/*
chmod 777 ~/.ssh/id_ed25519
git push --force origin main
dd if=/dev/zero of=/dev/sda
# Error message
BLOCKED: Dangerous command detected - rm -rf on root path
Command: rm -rf /var/log/*
Suspicious Patterns (WARN)¶
SUSPICIOUS_PATTERNS = [
(r'\bcurl\s+.*\|\s*bash', 'piping curl to bash'),
(r'\bwget\s+.*\|\s*bash', 'piping wget to bash'),
(r'\bnohup\s+', 'nohup background process'),
(r'&\s*$', 'backgrounding command'),
]
Example Warnings:
# Allowed with warning
curl https://install.sh | bash
# Warning message
NOTICE: Suspicious command - piping curl to bash
Use Cases¶
- Prevent accidental data loss (rm -rf)
- Block overly permissive permissions (chmod 777)
- Prevent destructive Git operations (force push to main)
- Warn on potentially dangerous patterns (curl | bash)
3. mcp-param-validator.py¶
Purpose: Validate MCP tool parameters before execution.
Hook Type: PreToolUse (mcp__)
Location: /home/agent/.claude/hooks/mcp-param-validator.py
Validation Rules¶
- Required parameters: Ensure present
- Type validation: String/number/boolean checks
- Path traversal: Block
../in file paths - SQL injection: Block suspicious SQL patterns in queries
- Command injection: Block shell metacharacters in commands
Example Validations:
# Block path traversal
mcp__filesystem__read_file(path="/home/agent/../../etc/passwd")
# Result: BLOCKED
# Block SQL injection attempt
mcp__postgres__execute(query="SELECT * FROM users WHERE id='1' OR '1'='1'")
# Result: BLOCKED
# Allow normal operation
mcp__filesystem__read_file(path="/home/agent/memory/journal/2026-01-25.md")
# Result: ALLOWED
Use Cases¶
- Prevent path traversal attacks
- Block SQL injection attempts
- Validate required MCP parameters
- Ensure type safety
4. mcp-security-audit.py¶
Purpose: Log all MCP tool usage with risk-based flagging.
Hook Type: PostToolUse (mcp__)
Location: /home/agent/.claude/hooks/mcp-security-audit.py
Risk Levels¶
MCP_RISK_LEVELS = {
# HIGH RISK - Can execute code or access sensitive resources
'docker': 'high',
'postgres': 'high',
'filesystem': 'high',
'stackwiz': 'high',
# MEDIUM RISK - External API access, potential data exfiltration
'github': 'medium',
'google-workspace': 'medium',
'discord': 'medium',
'telegram': 'medium',
'vonage': 'medium',
# LOW RISK - Read-only or sandboxed
'memory': 'low',
'ollama': 'low',
'playwright': 'low',
'wallet': 'low',
}
Flagged Operations¶
High-risk operations that are always logged with full context:
HIGH_RISK_OPERATIONS = {
'docker': ['remove_container', 'remove_image', 'remove_volume', 'remove_network'],
'postgres': ['execute'], # DML operations
'filesystem': ['write_file', 'edit_file', 'move_file'],
'github': ['push_files', 'create_or_update_file', 'merge_pull_request'],
'stackwiz': ['manage_stack'], # Can remove stacks
}
Audit Log Format¶
Location: ~/memory/security/mcp-audit.jsonl
{
"timestamp": "2026-01-25T12:00:00Z",
"session_id": "abc123",
"mcp_server": "docker",
"operation": "remove_container",
"risk_level": "high",
"flagged": true,
"event": "PostToolUse",
"input_summary": {
"container_id": "aegis-dashboard",
"force": true
}
}
Sensitive Data Redaction¶
# Fields that are always redacted
SENSITIVE_FIELDS = ['password', 'token', 'secret', 'key', 'credential']
# Long values are truncated
if len(value) > 200:
sanitized_input[key] = value[:200] + '...[truncated]'
Use Cases¶
- Security forensics (who did what, when)
- Anomaly detection (unusual MCP usage patterns)
- Compliance auditing (SOC 2, GDPR)
- Cost tracking (expensive operations)
Querying Audit Logs¶
# Find all flagged operations
jq 'select(.flagged == true)' ~/memory/security/mcp-audit.jsonl
# Find all high-risk operations
jq 'select(.risk_level == "high")' ~/memory/security/mcp-audit.jsonl
# Find operations by session
jq 'select(.session_id == "abc123")' ~/memory/security/mcp-audit.jsonl | tail -20
# Find operations in last hour
jq --arg time "$(date -u -d '1 hour ago' --iso-8601=seconds)" \
'select(.timestamp > $time)' ~/memory/security/mcp-audit.jsonl
Additional Hooks (Non-Security)¶
cost-tracker.sh¶
Purpose: Log tool usage for cost analysis.
Hook Type: PostToolUse (all tools)
Location: /home/agent/.claude/hooks/cost-tracker.sh
Output: ~/memory/tool-usage.jsonl
episodic-recorder.py¶
Purpose: Record significant operations to episodic memory.
Hook Type: PostToolUse (Task, WebSearch, Bash, Edit, Write, MCP)
Location: /home/agent/.claude/hooks/episodic-recorder.py
Output: ~/memory/episodic/ (JSONL files by date)
session-init.sh¶
Purpose: Initialize session (load Beads tasks, check autonomous mode).
Hook Type: SessionStart
Location: /home/agent/.claude/hooks/session-init.sh
quality-gate.sh¶
Purpose: Session hygiene checks (uncommitted changes, empty journal, open tasks).
Hook Type: Stop
Location: /home/agent/.claude/hooks/quality-gate.sh
autonomous-continue.sh¶
Purpose: Auto-continue Claude Code during autonomous mode.
Hook Type: Stop
Location: /home/agent/.claude/hooks/autonomous-continue.sh
Hook Development Best Practices¶
Exit Codes¶
import sys
sys.exit(0) # Allow operation
sys.exit(1) # Non-blocking error (log and continue)
sys.exit(2) # Block operation (prevent execution)
Input Format¶
Hooks receive JSON via stdin:
import json
import sys
data = json.load(sys.stdin)
tool_name = data.get('tool_name', '')
tool_input = data.get('tool_input', {})
session_id = data.get('session_id', 'unknown')
hook_event = data.get('hook_event_name', 'unknown')
Error Handling¶
try:
# Hook logic
sys.exit(0)
except Exception as e:
print(f"Hook error: {e}", file=sys.stderr)
sys.exit(1) # Non-blocking error
Logging¶
Always log to stderr for visibility:
print(f"BLOCKED: Reason for blocking", file=sys.stderr)
print(f"CAUTION: Warning message", file=sys.stderr)
Performance¶
- Keep hooks fast (<100ms)
- Use regex for pattern matching
- Avoid network calls
- Cache expensive operations
Testing¶
# Test a hook manually
echo '{"tool_name": "Write", "tool_input": {"file_path": "/home/agent/.ssh/id_rsa"}}' | \
/home/agent/.claude/hooks/block-sensitive-files.py
# Check exit code
echo $? # 2 = blocked, 0 = allowed
Security Hook Maintenance¶
Adding New Protected Files¶
Edit block-sensitive-files.py:
PROTECTED_PATTERNS = [
r'\.pem$',
r'\.key$',
r'id_rsa',
r'id_ed25519',
r'/\.git/',
r'new_pattern', # Add here
]
Adding New Dangerous Commands¶
Edit bash-validator.py:
DANGEROUS_PATTERNS = [
(r'\brm\s+-rf\s+/', 'rm -rf on root path'),
(r'\bnew_pattern', 'description'), # Add here
]
Adjusting MCP Risk Levels¶
Edit mcp-security-audit.py:
MCP_RISK_LEVELS = {
'docker': 'high',
'new-server': 'medium', # Add new servers here
}
HIGH_RISK_OPERATIONS = {
'docker': ['remove_container'],
'new-server': ['dangerous_operation'], # Add flagged ops here
}
Bypassing Hooks (Emergency)¶
WARNING: Only bypass hooks in emergency situations.
Temporary Bypass¶
- Stop Claude Code
- Edit
~/.claude/settings.json - Comment out the hook:
- Restart Claude Code
- REMEMBER TO RE-ENABLE AFTER
Permanent Bypass (Not Recommended)¶
# Disable hook by renaming
mv /home/agent/.claude/hooks/bash-validator.py \
/home/agent/.claude/hooks/bash-validator.py.disabled
Monitoring and Alerts¶
Daily Hook Reports¶
# Count blocked operations today
jq 'select(.timestamp | startswith("2026-01-25"))' \
~/memory/security/mcp-audit.jsonl | wc -l
# Find most-used MCP servers
jq -r '.mcp_server' ~/memory/security/mcp-audit.jsonl | sort | uniq -c | sort -nr
Alert on Suspicious Activity¶
Create a cron job to alert on flagged operations:
# /home/agent/.claude/hooks/alert-on-flagged.sh
#!/bin/bash
FLAGGED=$(jq 'select(.flagged == true and .timestamp > (now - 3600 | todate))' \
~/memory/security/mcp-audit.jsonl | wc -l)
if [ "$FLAGGED" -gt 5 ]; then
# Post to Discord #alerts
curl -X POST https://aegisagent.ai/api/discord/alert \
-d "text=WARNING: $FLAGGED flagged MCP operations in last hour"
fi
Compliance and Auditing¶
SOC 2 Controls¶
| Control | Hook Implementation |
|---|---|
| Access Logging | mcp-security-audit.py logs all MCP access |
| Least Privilege | MCP risk levels enforce (high/medium/low) |
| Change Management | episodic-recorder.py logs all Write/Edit operations |
| Dangerous Operations | bash-validator.py blocks destructive commands |
GDPR Controls¶
| Requirement | Hook Implementation |
|---|---|
| Data Access Logs | mcp-audit.jsonl provides trail |
| Data Deletion | Log requests via mcp-security-audit.py |
| Consent Management | (Not implemented - manual process) |
Audit Report Generation¶
# Generate monthly security report
cat <<EOF > ~/memory/security/report-2026-01.md
# Security Report - January 2026
## Summary
- Total MCP operations: $(jq -s 'length' ~/memory/security/mcp-audit.jsonl)
- Flagged operations: $(jq -s 'map(select(.flagged == true)) | length' ~/memory/security/mcp-audit.jsonl)
- Blocked bash commands: $(grep -c "BLOCKED" ~/.claude/hooks/*.log 2>/dev/null || echo 0)
## Top MCP Servers
$(jq -r '.mcp_server' ~/memory/security/mcp-audit.jsonl | sort | uniq -c | sort -nr | head -5)
## Flagged Operations
$(jq 'select(.flagged == true)' ~/memory/security/mcp-audit.jsonl | head -10)
EOF
Troubleshooting¶
Hook Not Firing¶
- Check
~/.claude/settings.jsonsyntax - Verify hook script has execute permissions:
- Test hook manually with sample input
- Check Claude Code logs:
~/.claude/logs/
Hook Timing Out¶
- Increase timeout in
settings.json: - Optimize hook script (remove slow operations)
Hook Producing Wrong Result¶
- Test with verbose logging:
- Check exit code behavior (0/1/2)
Future Enhancements¶
Planned (v2.0)¶
- Machine learning anomaly detection on MCP audit logs
- Real-time alerting to Discord/Telegram on flagged operations
- Rate limiting for expensive MCP operations
- Approval workflow for high-risk operations (human-in-the-loop)
- Compliance report generation (SOC 2, GDPR, ISO 27001)
- Integration with external SIEM (Splunk, Datadog)
Under Consideration¶
- Encrypted audit logs (GPG)
- Multi-user support with per-user MCP access control
- Automated incident response (e.g., revoke API keys on suspicious activity)
- Hook A/B testing framework (gradual rollout of new hooks)