Skip to content

Safety Hooks

Claude Code safety infrastructure that prevents accidental damage and provides audit logging.

Overview

Three hooks protect this infrastructure:

Hook Type Purpose
dangerous-command-blocker.py PreToolUse Block catastrophic commands
production-service-guard.py PreToolUse Confirm critical service operations
audit-logger.py PostToolUse Log all tool executions

Dangerous Command Blocker

Location: .claude/hooks/PreToolUse/dangerous-command-blocker.py

Blocked Patterns

Pattern Description
rm -rf / Removing root filesystem
rm -rf /* Removing all root contents
docker system prune -a Docker system prune all
DROP DATABASE SQL DROP DATABASE
TRUNCATE TABLE SQL TRUNCATE TABLE
mkfs Filesystem format commands
dd if=.* of=/dev/ Direct disk writes
> /dev/sd Overwriting disk devices
chmod -R 777 / Dangerous permission changes
chown -R .* / Dangerous ownership changes

System Directory Protection

Writes to these directories are blocked: - /etc/ - System configuration - /usr/ - System binaries - /boot/ - Boot files - /sys/ - Kernel interface - /proc/ - Process information

Bypass

If a blocked command is legitimately needed: 1. The hook returns a BLOCK decision with explanation 2. You must manually execute the command outside Claude Code 3. This ensures human verification of dangerous operations

Production Service Guard

Location: .claude/hooks/PreToolUse/production-service-guard.py

Protected Services

supa-db          - PostgreSQL database
traefik          - Reverse proxy
prometheus       - Metrics collection
grafana          - Dashboards
alertmanager     - Alert routing
loki             - Log aggregation
authentik        - SSO provider
adguard          - DNS filtering
gitea            - Git server
cache-redis      - Shared cache
session-redis    - Session storage

Protected Operations

These operations on protected services require confirmation: - stop - Stopping containers - down - Bringing down compose stacks - rm - Removing containers - remove - Removing containers - kill - Killing containers - restart - Restarting containers

Confirmation Required

When a protected operation is detected, Claude will ask for confirmation before proceeding. This prevents accidental disruption of critical services.

Example blocked operation:

docker compose -f supabase/docker-compose.yml down
# Requires confirmation: "Stop critical service supa-db?"

Audit Logger

Location: .claude/hooks/PostToolUse/audit-logger.py

Log Format

Each entry includes: - timestamp: ISO 8601 format - session_id: Claude session identifier - tool: Tool name (Bash, Read, Write, etc.) - input_summary: First 200 characters of input - output_status: success/error

Log Location

/srv/dockerdata/.claude/logs/audit.log

Example Log Entry

{
  "timestamp": "2025-12-04T10:30:45.123456",
  "session_id": "abc123",
  "tool": "Bash",
  "input_summary": "docker ps --format \"table {{.Names}}\\t{{.Status}}\"",
  "output_status": "success"
}

Viewing Logs

# Recent activity
tail -50 /srv/dockerdata/.claude/logs/audit.log

# Today's Bash commands
grep "$(date +%Y-%m-%d)" /srv/dockerdata/.claude/logs/audit.log | grep '"tool": "Bash"'

# Count operations by tool
grep -o '"tool": "[^"]*"' /srv/dockerdata/.claude/logs/audit.log | sort | uniq -c | sort -rn

# Find errors
grep '"output_status": "error"' /srv/dockerdata/.claude/logs/audit.log

Log Rotation

Audit logs grow over time. Consider rotating:

# Manual rotation
mv /srv/dockerdata/.claude/logs/audit.log /srv/dockerdata/.claude/logs/audit.log.$(date +%Y%m%d)
touch /srv/dockerdata/.claude/logs/audit.log

Hook Configuration

Hooks are registered in .claude/settings.local.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /srv/dockerdata/.claude/hooks/PreToolUse/dangerous-command-blocker.py"
          },
          {
            "type": "command",
            "command": "python3 /srv/dockerdata/.claude/hooks/PreToolUse/production-service-guard.py"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "python3 /srv/dockerdata/.claude/hooks/PostToolUse/audit-logger.py"
          }
        ]
      }
    ]
  }
}

Creating Custom Hooks

Hook Input

Hooks receive JSON on stdin:

{
  "tool_name": "Bash",
  "tool_input": {
    "command": "docker ps"
  }
}

Hook Output

Hooks output JSON decision:

{
  "decision": "ALLOW"
}

Or to block:

{
  "decision": "BLOCK",
  "reason": "Explanation of why blocked"
}

Hook Template

#!/usr/bin/env python3
import json
import sys

def main():
    # Read input from stdin
    input_data = json.loads(sys.stdin.read())

    tool_name = input_data.get('tool_name', '')
    tool_input = input_data.get('tool_input', {})

    # Your logic here
    should_block = False
    reason = ""

    if should_block:
        result = {"decision": "BLOCK", "reason": reason}
    else:
        result = {"decision": "ALLOW"}

    print(json.dumps(result))

if __name__ == "__main__":
    main()