From 14cb0f4d7b5470f25eefdfa21ea25f4bd58a3d85 Mon Sep 17 00:00:00 2001 From: Snider Date: Mon, 2 Feb 2026 07:13:28 +0000 Subject: [PATCH] feat(code): add secret detection hook (#67) This change introduces a new hook that runs before a file is written or edited. The hook executes a script that scans the file content for patterns that match common secret formats, such as API keys, AWS keys, and private keys. If a potential secret is found, the script exits with a non-zero status code, which blocks the file operation and prevents the secret from being committed. The script also provides a user-friendly error message with the filename, line number, and a suggestion to use environment variables. This helps to prevent accidental commits of sensitive credentials to the repository. --- claude/code/hooks.json | 10 ++++ claude/code/scripts/detect-secrets.sh | 73 +++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100755 claude/code/scripts/detect-secrets.sh diff --git a/claude/code/hooks.json b/claude/code/hooks.json index fc38fe6..57a4dff 100644 --- a/claude/code/hooks.json +++ b/claude/code/hooks.json @@ -21,6 +21,16 @@ } ], "description": "Block random .md file creation" + }, + { + "matcher": "tool == \"Write\" || tool == \"Edit\"", + "hooks": [ + { + "type": "command", + "command": "echo \"${tool_input.content}\" | ${CLAUDE_PLUGIN_ROOT}/scripts/detect-secrets.sh ${tool_input.filepath}" + } + ], + "description": "Detect secrets in code before writing or editing files." } ], "PostToolUse": [ diff --git a/claude/code/scripts/detect-secrets.sh b/claude/code/scripts/detect-secrets.sh new file mode 100755 index 0000000..2de409f --- /dev/null +++ b/claude/code/scripts/detect-secrets.sh @@ -0,0 +1,73 @@ +#!/bin/bash + +# Patterns for detecting secrets +PATTERNS=( + # API keys (e.g., sk_live_..., ghp_..., etc.) + "[a-zA-Z0-9]{32,}" + # AWS keys + "AKIA[0-9A-Z]{16}" + # Private keys + "-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----" + # Passwords in config + "(password|passwd|pwd)\s*[=:]\s*['\"][^'\"]+['\"]" + # Tokens + "(token|secret|key)\s*[=:]\s*['\"][^'\"]+['\"]" +) + +# Exceptions for fake secrets +EXCEPTIONS=( + "password123" + "your-api-key-here" + "xxx" + "test" + "example" +) + +# File to check is passed as the first argument +FILE_PATH=$1 + +# Function to check for secrets +check_secrets() { + local input_source="$1" + local file_path="$2" + local line_num=0 + while IFS= read -r line; do + line_num=$((line_num + 1)) + for pattern in "${PATTERNS[@]}"; do + if echo "$line" | grep -qE "$pattern"; then + # Check for exceptions + is_exception=false + for exception in "${EXCEPTIONS[@]}"; do + if echo "$line" | grep -qF "$exception"; then + is_exception=true + break + fi + done + + if [ "$is_exception" = false ]; then + echo "⚠️ Potential secret detected!" + echo "File: $file_path" + echo "Line: $line_num" + echo "" + echo "Found: $line" + echo "" + echo "This looks like a production secret." + echo "Use environment variables instead." + echo "" + + # Propose a fix (example for a PHP config file) + if [[ "$file_path" == *.php ]]; then + echo "'stripe' => [" + echo " 'secret' => env('STRIPE_SECRET'), // ✓" + echo "]" + fi + exit 1 + fi + fi + done + done < "$input_source" +} + +check_secrets "/dev/stdin" "$FILE_PATH" + +exit 0