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.
This commit is contained in:
parent
394d11d9d2
commit
14cb0f4d7b
2 changed files with 83 additions and 0 deletions
|
|
@ -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": [
|
||||
|
|
|
|||
73
claude/code/scripts/detect-secrets.sh
Executable file
73
claude/code/scripts/detect-secrets.sh
Executable file
|
|
@ -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
|
||||
Loading…
Add table
Reference in a new issue