#!/bin/bash # Check for secrets in files before writing # Exit code 2 blocks the operation in Claude Code set -e # Read the file path from stdin (Claude passes tool_input as JSON) INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | jq -r '.file_path // .filePath // empty') if [ -z "$FILE_PATH" ]; then exit 0 fi # Skip non-code files case "$FILE_PATH" in *.md|*.txt|*.json|*.yaml|*.yml|*.toml|*.lock|*.svg|*.png|*.jpg|*.gif) exit 0 ;; esac # Patterns that indicate secrets SECRET_PATTERNS=( 'password\s*=\s*["\x27][^"\x27]+' 'api[_-]?key\s*=\s*["\x27][^"\x27]+' 'secret[_-]?key\s*=\s*["\x27][^"\x27]+' 'aws[_-]?access[_-]?key[_-]?id\s*=\s*["\x27][A-Z0-9]+' 'aws[_-]?secret[_-]?access[_-]?key\s*=\s*["\x27][^"\x27]+' 'private[_-]?key\s*=\s*["\x27][^"\x27]+' 'database[_-]?url\s*=\s*["\x27]postgres(ql)?://[^"\x27]+' 'mongodb(\+srv)?://[^"\x27\s]+' 'redis://[^"\x27\s]+' 'AKIA[0-9A-Z]{16}' 'ghp_[a-zA-Z0-9]{36}' 'sk-[a-zA-Z0-9]{48}' 'xox[baprs]-[0-9a-zA-Z-]+' ) # Check if file exists and scan for secrets if [ -f "$FILE_PATH" ]; then for pattern in "${SECRET_PATTERNS[@]}"; do if grep -qiE "$pattern" "$FILE_PATH" 2>/dev/null; then echo "BLOCKED: Potential secret detected in $FILE_PATH" echo "Pattern matched: $pattern" echo "Please use environment variables or secrets manager instead." exit 2 fi done fi exit 0