claude-code-ultimate-guide/examples/hooks/bash/repo-integrity-scanner.sh
Florian BRUNIAUX 34b2ca7200 feat(security): add security hardening guide and hooks v3.6.0
- Add guide/security-hardening.md (~10K) covering:
  - MCP vetting workflow with CVE-2025-53109/53110, 54135, 54136
  - Prompt injection evasion techniques (Unicode, ANSI, null bytes)
  - Secret detection tool comparison (Gitleaks, TruffleHog, GitGuardian)
  - Incident response procedures

- Add 3 new security hooks:
  - unicode-injection-scanner.sh: zero-width, RTL, ANSI escape detection
  - repo-integrity-scanner.sh: scan README/package.json for injection
  - mcp-config-integrity.sh: verify MCP config hash

- Update existing hooks:
  - prompt-injection-detector.sh: +ANSI, +null bytes, +nested cmd
  - output-secrets-scanner.sh: +env leakage, +generic tokens

- Update cross-references in ultimate-guide.md (§7.4, §8.6)
- Move MCP Security Hardening to Done in IDEAS.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 07:39:53 +01:00

215 lines
6.3 KiB
Bash
Executable file

#!/bin/bash
# =============================================================================
# Repository Integrity Scanner Hook
# =============================================================================
# Event: PreToolUse (runs before Read on potentially malicious files)
# Purpose: Scan repository files for injection vectors before processing
#
# This hook detects prompt injection attempts hidden in:
# - README.md, SECURITY.md (hidden HTML comments)
# - package.json, pyproject.toml (malicious scripts)
# - .claude/, .cursor/ configs (tampered configurations)
# - CONTRIBUTING.md (social engineering instructions)
#
# Installation:
# Add to .claude/settings.json:
# {
# "hooks": {
# "PreToolUse": [{
# "matcher": "Read",
# "hooks": ["bash examples/hooks/bash/repo-integrity-scanner.sh"]
# }]
# }
# }
#
# Exit codes:
# 0 = allow (safe or not a target file)
# 2 = block (injection detected)
#
# References:
# - CVE-2025-54135: RCE via config file rewriting
# - CVE-2025-54136: Team backdoor via post-approval config tampering
# =============================================================================
set -euo pipefail
# Read the hook input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
TOOL_INPUT=$(echo "$INPUT" | jq -r '.tool_input // empty')
# Only check Read operations
[[ "$TOOL_NAME" != "Read" ]] && exit 0
FILE_PATH=$(echo "$TOOL_INPUT" | jq -r '.file_path // empty')
[[ -z "$FILE_PATH" ]] && exit 0
# Check if file exists
[[ ! -f "$FILE_PATH" ]] && exit 0
FILENAME=$(basename "$FILE_PATH")
DIRNAME=$(dirname "$FILE_PATH")
# === HIGH-RISK FILES ===
# These files are common injection vectors
HIGH_RISK_FILES=(
"README.md"
"readme.md"
"SECURITY.md"
"CONTRIBUTING.md"
"CHANGELOG.md"
)
# === CONFIG FILES ===
# Configuration files that could contain malicious settings
CONFIG_FILES=(
"package.json"
"pyproject.toml"
"setup.py"
"setup.cfg"
"Makefile"
".pre-commit-config.yaml"
)
# === CLAUDE/CURSOR CONFIG ===
# IDE config files that could be tampered
IDE_CONFIG_PATTERNS=(
".claude"
".cursor"
".vscode"
".idea"
)
# Function to check for injection patterns
check_injection_patterns() {
local file="$1"
local content
content=$(cat "$file" 2>/dev/null || echo "")
# === HIDDEN HTML COMMENTS ===
# Look for HTML comments with instruction-like content
if echo "$content" | grep -qiE '<!--.*\b(ignore|override|system|execute|run|eval|inject)\b.*-->'; then
echo "BLOCKED: Hidden HTML comment with suspicious instructions in: $file" >&2
return 1
fi
# === ROLE OVERRIDE PATTERNS ===
if echo "$content" | grep -qiE 'ignore (previous|all|your) instructions|you are now|pretend (you are|to be)|from now on|new instructions:'; then
echo "BLOCKED: Prompt injection pattern detected in: $file" >&2
return 1
fi
# === BASE64 IN COMMENTS ===
# Long base64 strings in comments could be encoded instructions
if echo "$content" | grep -qE '(#|//|<!--).*[A-Za-z0-9+/]{40,}={0,2}'; then
# Try to decode and check for injection
local encoded
encoded=$(echo "$content" | grep -oE '[A-Za-z0-9+/]{40,}={0,2}' | head -1)
local decoded
decoded=$(echo "$encoded" | base64 -d 2>/dev/null || echo "")
if echo "$decoded" | grep -qiE 'ignore|override|system|jailbreak'; then
echo "BLOCKED: Base64-encoded injection detected in: $file" >&2
return 1
fi
fi
return 0
}
# Function to check package.json for suspicious scripts
check_package_json() {
local file="$1"
# Extract scripts section
local scripts
scripts=$(jq -r '.scripts // {} | to_entries[] | "\(.key): \(.value)"' "$file" 2>/dev/null || echo "")
# Suspicious script patterns
SUSPICIOUS_PATTERNS=(
"curl.*|.*bash"
"wget.*|.*sh"
"eval\("
"base64.*-d"
"nc -"
"reverse.*shell"
"/dev/tcp/"
"\\$\\(.*\\)" # Command substitution
)
for pattern in "${SUSPICIOUS_PATTERNS[@]}"; do
if echo "$scripts" | grep -qiE "$pattern"; then
echo "BLOCKED: Suspicious npm script detected in $file: pattern '$pattern'" >&2
return 1
fi
done
return 0
}
# Function to check Python setup files
check_python_setup() {
local file="$1"
local content
content=$(cat "$file" 2>/dev/null || echo "")
# Suspicious patterns in setup files
if echo "$content" | grep -qiE 'os\.system|subprocess\.(run|call|Popen)|exec\(|eval\(|__import__.*os'; then
# Warning only - these could be legitimate
echo '{"systemMessage": "Warning: Python setup file contains code execution patterns. Verify legitimacy before installing."}'
fi
return 0
}
# === MAIN CHECKS ===
# Check high-risk markdown files
for risk_file in "${HIGH_RISK_FILES[@]}"; do
if [[ "$FILENAME" == "$risk_file" ]]; then
check_injection_patterns "$FILE_PATH" || exit 2
break
fi
done
# Check config files
for config_file in "${CONFIG_FILES[@]}"; do
if [[ "$FILENAME" == "$config_file" ]]; then
case "$FILENAME" in
package.json)
check_package_json "$FILE_PATH" || exit 2
;;
pyproject.toml|setup.py|setup.cfg)
check_python_setup "$FILE_PATH" || exit 2
;;
Makefile)
check_injection_patterns "$FILE_PATH" || exit 2
;;
esac
break
fi
done
# Check IDE config directories
for ide_pattern in "${IDE_CONFIG_PATTERNS[@]}"; do
if [[ "$DIRNAME" == *"$ide_pattern"* || "$FILE_PATH" == *"$ide_pattern"* ]]; then
# Extra scrutiny for IDE configs
check_injection_patterns "$FILE_PATH" || exit 2
# Check for suspicious config modifications
if [[ "$FILENAME" == *.json ]]; then
local content
content=$(cat "$FILE_PATH" 2>/dev/null || echo "")
# Look for hooks pointing to external URLs or suspicious commands
if echo "$content" | grep -qiE '"hooks".*"(curl|wget|bash|sh|nc|python|node)'; then
echo "BLOCKED: Suspicious hook command in IDE config: $FILE_PATH" >&2
exit 2
fi
fi
break
fi
done
# All checks passed
exit 0