#!/bin/bash # Blocks edits to sensitive or generated files. # Used as a PreToolUse hook for Edit|Write operations. # Exit 2 = block the action. Exit 0 = allow. # Requires jq for JSON parsing — fail closed if missing if ! command -v jq >/dev/null 2>&1; then echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"jq is required for file protection hooks but is not installed.\"}}" exit 2 fi INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') if [ -z "$FILE_PATH" ]; then exit 0 fi # Protected patterns — add your own PROTECTED_PATTERNS=( ".env" ".env.*" "*.pem" "*.key" "*.crt" "*.p12" "*.pfx" "id_rsa" "id_ed25519" "credentials.json" ".npmrc" ".pypirc" "package-lock.json" "yarn.lock" "pnpm-lock.yaml" "*.gen.ts" "*.generated.*" "*.min.js" "*.min.css" ) BASENAME=$(basename "$FILE_PATH") for pattern in "${PROTECTED_PATTERNS[@]}"; do case "$BASENAME" in $pattern) echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Protected file: $BASENAME matches pattern '$pattern'\"}}" exit 2 ;; esac done # Block anything in common sensitive directories (handles both relative and absolute paths) case "$FILE_PATH" in .git/*|*/.git/*) echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit files inside .git/\"}}" exit 2 ;; secrets/*|*/secrets/*) echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit files inside secrets/\"}}" exit 2 ;; .env|.env.*|*/.env|*/.env.*) echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit .env files\"}}" exit 2 ;; .claude/hooks/*|*/.claude/hooks/*) echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"Cannot edit hook scripts — these enforce security boundaries.\"}}" exit 2 ;; .claude/settings.json|*/.claude/settings.json) echo "{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"ask\",\"permissionDecisionReason\":\"Editing settings.json — this controls permissions and hooks. Confirm this change.\"}}" exit 2 ;; esac exit 0