#!/bin/bash# Security scan on file write# Hook: PostToolUse:Write## Scans files for hardcoded secrets, API keys, and credentials.# Outputs a non-blocking warning via additionalContext when issues are found.## Compatible with: macOS, Linux, Windows (Git Bash)# Read JSON input from stdin (Claude Code hook protocol)
INPUT=$(cat)
# Extract file_path using sed (compatible with all platforms including Windows Git Bash)# Avoids grep -P (not available on Windows Git Bash) and python3 dependency
FILE_PATH=$(echo"$INPUT" | sed -n 's/.*"file_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; thenexit 0
fi# Skip binary files, vendor dirs, and build artifactscase"$FILE_PATH"in
*.png|*.jpg|*.jpeg|*.gif|*.svg|*.ico|*.woff|*.woff2|*.ttf|*.eot) exit 0 ;;
*/node_modules/*|*/.git/*|*/dist/*|*/build/*) exit 0 ;;
esac
ISSUES=""# Check for hardcoded passwords# Handles both JSON format ("password": "value") and code format (password = 'value')# Use \\n as separator — it is a valid JSON newline escape and passes through printf safelyif grep -qiE '"password"[[:space:]]*:[[:space:]]*"[^"]+"'"$FILE_PATH" 2>/dev/null; then
ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\\n"elif grep -qiE '(password|passwd|pwd)[[:space:]]*=[[:space:]]*'"'"'[^'"'"']+'"'"''"$FILE_PATH" 2>/dev/null; then
ISSUES="${ISSUES}- WARNING: Potential hardcoded password detected\\n"fi# Check for hardcoded API keysif grep -qiE '"(api[_-]?key|apikey|access[_-]?token)"[[:space:]]*:[[:space:]]*"[^"]+"'"$FILE_PATH" 2>/dev/null; then
ISSUES="${ISSUES}- WARNING: Potential hardcoded API key detected\\n"fi# Check for hardcoded secrets and tokensif grep -qiE '(secret|token)[[:space:]]*=[[:space:]]*['"'"'"][^'"'"'"]+['"'"'"]'"$FILE_PATH" 2>/dev/null; then
ISSUES="${ISSUES}- WARNING: Potential hardcoded secret or token detected\\n"fi# Check for private keysif grep -q "BEGIN.*PRIVATE KEY""$FILE_PATH" 2>/dev/null; then
ISSUES="${ISSUES}- WARNING: Private key detected\\n"fi# Check for AWS keysif grep -qE "AKIA[0-9A-Z]{16}""$FILE_PATH" 2>/dev/null; then
ISSUES="${ISSUES}- WARNING: AWS access key detected\\n"fi# Scan with semgrep if available (stdout suppressed to avoid mixing with JSON output)ifcommand -v semgrep &> /dev/null; then
semgrep --config=auto "$FILE_PATH" --quiet >/dev/null 2>/dev/null
fi# Scan with trufflehog if available (stdout suppressed to avoid mixing with JSON output)ifcommand -v trufflehog &> /dev/null; then
trufflehog filesystem "$FILE_PATH" --only-verified --quiet >/dev/null 2>/dev/null
fi# If issues found, output as additionalContext (non-blocking warning)# Use hookSpecificOutput format required by Claude Code PostToolUse protocolif [ -n "$ISSUES" ]; then# Escape file path for JSON (backslash and double-quote)# ISSUES already uses \\n as separator (valid JSON escape) — only escape double-quotes
SAFE_PATH=$(printf'%s'"$FILE_PATH" | sed 's/\\/\\\\/g; s/"/\\"/g')
SAFE_ISSUES=$(printf'%s'"$ISSUES" | sed 's/"/\\"/g')
printf'{"hookSpecificOutput": {"hookEventName": "PostToolUse", "additionalContext": "Security scan found issues in %s:\\n%sPlease review and use environment variables instead."}}'"$SAFE_PATH""$SAFE_ISSUES"fiexit 0