Loading...
Scans for security vulnerabilities when package.json or requirements.txt files are modified
{
"hookConfig": {
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/package-vulnerability-scanner.sh",
"matchers": [
"write",
"edit"
]
}
}
},
"scriptContent": "#!/usr/bin/env bash\n\n# Read the tool input from stdin\nINPUT=$(cat)\nTOOL_NAME=$(echo \"$INPUT\" | jq -r '.tool_name')\nFILE_PATH=$(echo \"$INPUT\" | jq -r '.tool_input.file_path // .tool_input.path // \"\"')\n\nif [ -z \"$FILE_PATH\" ]; then\n exit 0\nfi\n\n# Check if this is a dependency or package file\nif [[ \"$FILE_PATH\" == *package.json ]] || [[ \"$FILE_PATH\" == *requirements.txt ]] || [[ \"$FILE_PATH\" == *Pipfile ]] || [[ \"$FILE_PATH\" == *Gemfile ]] || [[ \"$FILE_PATH\" == *go.mod ]] || [[ \"$FILE_PATH\" == *yarn.lock ]] || [[ \"$FILE_PATH\" == *package-lock.json ]] || [[ \"$FILE_PATH\" == *composer.json ]]; then\n echo \"๐ Package Vulnerability Scanner for: $(basename \"$FILE_PATH\")\" >&2\n \n # Initialize security counters\n TOTAL_VULNERABILITIES=0\n HIGH_SEVERITY=0\n MEDIUM_SEVERITY=0\n LOW_SEVERITY=0\n CRITICAL_SEVERITY=0\n FIXABLE_VULNERABILITIES=0\n ERRORS=0\n WARNINGS=0\n \n # Function to report security findings\n report_security() {\n local level=\"$1\"\n local message=\"$2\"\n \n case \"$level\" in\n \"CRITICAL\")\n echo \"๐จ CRITICAL: $message\" >&2\n ERRORS=$((ERRORS + 1))\n ;;\n \"ERROR\")\n echo \"โ ERROR: $message\" >&2\n ERRORS=$((ERRORS + 1))\n ;;\n \"WARNING\")\n echo \"โ ๏ธ WARNING: $message\" >&2\n WARNINGS=$((WARNINGS + 1))\n ;;\n \"INFO\")\n echo \"โน๏ธ INFO: $message\" >&2\n ;;\n \"PASS\")\n echo \"โ
PASS: $message\" >&2\n ;;\n esac\n }\n \n # Detect package manager and language\n PACKAGE_MANAGER=\"\"\n LANGUAGE=\"\"\n SCAN_COMMAND=\"\"\n \n FILE_NAME=$(basename \"$FILE_PATH\")\n FILE_DIR=$(dirname \"$FILE_PATH\")\n \n echo \"๐ Analyzing package file: $FILE_NAME\" >&2\n \n # Determine package manager and language\n case \"$FILE_NAME\" in\n \"package.json\")\n PACKAGE_MANAGER=\"npm\"\n LANGUAGE=\"Node.js\"\n ;;\n \"yarn.lock\")\n PACKAGE_MANAGER=\"yarn\"\n LANGUAGE=\"Node.js\"\n ;;\n \"package-lock.json\")\n PACKAGE_MANAGER=\"npm\"\n LANGUAGE=\"Node.js\"\n ;;\n \"requirements.txt\")\n PACKAGE_MANAGER=\"pip\"\n LANGUAGE=\"Python\"\n ;;\n \"Pipfile\")\n PACKAGE_MANAGER=\"pipenv\"\n LANGUAGE=\"Python\"\n ;;\n \"Gemfile\")\n PACKAGE_MANAGER=\"bundler\"\n LANGUAGE=\"Ruby\"\n ;;\n \"go.mod\")\n PACKAGE_MANAGER=\"go\"\n LANGUAGE=\"Go\"\n ;;\n \"composer.json\")\n PACKAGE_MANAGER=\"composer\"\n LANGUAGE=\"PHP\"\n ;;\n *)\n report_security \"WARNING\" \"Unknown package file type: $FILE_NAME\"\n exit 0\n ;;\n esac\n \n echo \" ๐ง Package Manager: $PACKAGE_MANAGER\" >&2\n echo \" ๐ Language: $LANGUAGE\" >&2\n \n # 1. Node.js Security Scanning\n if [[ \"$PACKAGE_MANAGER\" == \"npm\" ]] || [[ \"$PACKAGE_MANAGER\" == \"yarn\" ]]; then\n echo \"๐ฆ Node.js security scanning...\" >&2\n \n # Check if npm is available\n if command -v npm &> /dev/null; then\n echo \" ๐ Running npm audit...\" >&2\n \n NPM_AUDIT_OUTPUT=\"/tmp/npm_audit_$$\"\n \n # Run npm audit with JSON output\n if npm audit --json > \"$NPM_AUDIT_OUTPUT\" 2>&1; then\n # Parse npm audit results\n if command -v jq &> /dev/null; then\n AUDIT_SUMMARY=$(jq -r '.metadata.vulnerabilities' \"$NPM_AUDIT_OUTPUT\" 2>/dev/null || echo '{}')\n \n if [ \"$AUDIT_SUMMARY\" != \"{}\" ] && [ \"$AUDIT_SUMMARY\" != \"null\" ]; then\n # Extract vulnerability counts\n CRITICAL_COUNT=$(echo \"$AUDIT_SUMMARY\" | jq -r '.critical // 0')\n HIGH_COUNT=$(echo \"$AUDIT_SUMMARY\" | jq -r '.high // 0')\n MODERATE_COUNT=$(echo \"$AUDIT_SUMMARY\" | jq -r '.moderate // 0')\n LOW_COUNT=$(echo \"$AUDIT_SUMMARY\" | jq -r '.low // 0')\n \n TOTAL_VULNERABILITIES=$((CRITICAL_COUNT + HIGH_COUNT + MODERATE_COUNT + LOW_COUNT))\n CRITICAL_SEVERITY=$CRITICAL_COUNT\n HIGH_SEVERITY=$HIGH_COUNT\n MEDIUM_SEVERITY=$MODERATE_COUNT\n LOW_SEVERITY=$LOW_COUNT\n \n echo \" ๐ Vulnerability summary:\" >&2\n echo \" ๐จ Critical: $CRITICAL_COUNT\" >&2\n echo \" ๐ด High: $HIGH_COUNT\" >&2\n echo \" ๐ก Moderate: $MODERATE_COUNT\" >&2\n echo \" ๐ข Low: $LOW_COUNT\" >&2\n \n if [ \"$CRITICAL_COUNT\" -gt 0 ]; then\n report_security \"CRITICAL\" \"$CRITICAL_COUNT critical vulnerabilities found\"\n fi\n \n if [ \"$HIGH_COUNT\" -gt 0 ]; then\n report_security \"ERROR\" \"$HIGH_COUNT high severity vulnerabilities found\"\n fi\n \n if [ \"$MODERATE_COUNT\" -gt 0 ]; then\n report_security \"WARNING\" \"$MODERATE_COUNT moderate severity vulnerabilities found\"\n fi\n \n # Show top vulnerabilities\n TOP_VULNS=$(jq -r '.vulnerabilities | to_entries | .[0:3] | .[] | \" โข \" + .key + \" (\" + .value.severity + \")\"' \"$NPM_AUDIT_OUTPUT\" 2>/dev/null || echo \"\")\n \n if [ -n \"$TOP_VULNS\" ]; then\n echo \" ๐ฏ Top vulnerabilities:\" >&2\n echo \"$TOP_VULNS\" >&2\n fi\n else\n report_security \"PASS\" \"No vulnerabilities found in npm dependencies\"\n fi\n else\n report_security \"WARNING\" \"jq not available - limited vulnerability parsing\"\n fi\n else\n # npm audit failed, check if it's due to vulnerabilities\n AUDIT_EXIT_CODE=$?\n \n if [ $AUDIT_EXIT_CODE -eq 1 ]; then\n # Exit code 1 means vulnerabilities found\n report_security \"ERROR\" \"npm audit found vulnerabilities (exit code 1)\"\n \n # Try to extract basic info\n VULN_COUNT=$(grep -o 'vulnerabilities' \"$NPM_AUDIT_OUTPUT\" 2>/dev/null | wc -l || echo \"0\")\n if [ \"$VULN_COUNT\" -gt 0 ]; then\n echo \" โ ๏ธ Estimated vulnerabilities: $VULN_COUNT\" >&2\n fi\n else\n report_security \"ERROR\" \"npm audit failed with exit code $AUDIT_EXIT_CODE\"\n fi\n fi\n \n rm -f \"$NPM_AUDIT_OUTPUT\"\n \n # Check for yarn if available\n if [[ \"$PACKAGE_MANAGER\" == \"yarn\" ]] && command -v yarn &> /dev/null; then\n echo \" ๐งถ Running yarn audit...\" >&2\n \n YARN_AUDIT_OUTPUT=\"/tmp/yarn_audit_$$\"\n \n if yarn audit --json > \"$YARN_AUDIT_OUTPUT\" 2>&1; then\n report_security \"PASS\" \"Yarn audit completed successfully\"\n else\n report_security \"WARNING\" \"Yarn audit found issues or failed\"\n fi\n \n rm -f \"$YARN_AUDIT_OUTPUT\"\n fi\n \n else\n report_security \"WARNING\" \"npm not available - cannot perform Node.js security scan\"\n fi\n fi\n \n # 2. Python Security Scanning\n if [[ \"$PACKAGE_MANAGER\" == \"pip\" ]] || [[ \"$PACKAGE_MANAGER\" == \"pipenv\" ]]; then\n echo \"๐ Python security scanning...\" >&2\n \n # Check for safety tool\n if command -v safety &> /dev/null; then\n echo \" ๐ Running safety check...\" >&2\n \n SAFETY_OUTPUT=\"/tmp/safety_output_$$\"\n \n if safety check --json > \"$SAFETY_OUTPUT\" 2>&1; then\n report_security \"PASS\" \"Safety check completed - no vulnerabilities found\"\n else\n # Safety found vulnerabilities\n SAFETY_EXIT_CODE=$?\n \n if [ $SAFETY_EXIT_CODE -eq 64 ]; then\n # Exit code 64 means vulnerabilities found\n report_security \"ERROR\" \"Safety found vulnerabilities in Python dependencies\"\n \n # Try to parse vulnerabilities\n if command -v jq &> /dev/null && [ -f \"$SAFETY_OUTPUT\" ]; then\n VULN_COUNT=$(jq length \"$SAFETY_OUTPUT\" 2>/dev/null || echo \"0\")\n \n if [ \"$VULN_COUNT\" -gt 0 ]; then\n echo \" ๐ Found $VULN_COUNT Python vulnerabilities\" >&2\n TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + VULN_COUNT))\n \n # Show first few vulnerabilities\n jq -r '.[0:3] | .[] | \" โข \" + .package + \" (\" + .vulnerability_id + \")\"' \"$SAFETY_OUTPUT\" 2>/dev/null | while read line; do\n echo \"$line\" >&2\n done\n fi\n fi\n else\n report_security \"WARNING\" \"Safety check failed with exit code $SAFETY_EXIT_CODE\"\n fi\n fi\n \n rm -f \"$SAFETY_OUTPUT\"\n \n elif command -v pip &> /dev/null; then\n echo \" ๐ Safety not available, using pip-audit if available...\" >&2\n \n if command -v pip-audit &> /dev/null; then\n PIP_AUDIT_OUTPUT=\"/tmp/pip_audit_$$\"\n \n if pip-audit --format=json > \"$PIP_AUDIT_OUTPUT\" 2>&1; then\n report_security \"PASS\" \"pip-audit completed - no vulnerabilities found\"\n else\n report_security \"ERROR\" \"pip-audit found vulnerabilities in Python dependencies\"\n fi\n \n rm -f \"$PIP_AUDIT_OUTPUT\"\n else\n report_security \"WARNING\" \"No Python security tools available (safety, pip-audit)\"\n fi\n else\n report_security \"WARNING\" \"Python/pip not available - cannot perform Python security scan\"\n fi\n fi\n \n # 3. Ruby Security Scanning\n if [[ \"$PACKAGE_MANAGER\" == \"bundler\" ]]; then\n echo \"๐ Ruby security scanning...\" >&2\n \n if command -v bundler-audit &> /dev/null; then\n echo \" ๐ Running bundler-audit...\" >&2\n \n BUNDLER_AUDIT_OUTPUT=\"/tmp/bundler_audit_$$\"\n \n if bundler-audit check > \"$BUNDLER_AUDIT_OUTPUT\" 2>&1; then\n report_security \"PASS\" \"bundler-audit completed - no vulnerabilities found\"\n else\n report_security \"ERROR\" \"bundler-audit found vulnerabilities in Ruby dependencies\"\n \n # Count vulnerabilities\n RUBY_VULNS=$(grep -c 'Vulnerability found' \"$BUNDLER_AUDIT_OUTPUT\" 2>/dev/null || echo \"0\")\n if [ \"$RUBY_VULNS\" -gt 0 ]; then\n echo \" ๐ Found $RUBY_VULNS Ruby vulnerabilities\" >&2\n TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + RUBY_VULNS))\n fi\n fi\n \n rm -f \"$BUNDLER_AUDIT_OUTPUT\"\n else\n report_security \"WARNING\" \"bundler-audit not available - install with 'gem install bundler-audit'\"\n fi\n fi\n \n # 4. Go Security Scanning\n if [[ \"$PACKAGE_MANAGER\" == \"go\" ]]; then\n echo \"๐น Go security scanning...\" >&2\n \n if command -v govulncheck &> /dev/null; then\n echo \" ๐ Running govulncheck...\" >&2\n \n GOVULN_OUTPUT=\"/tmp/govuln_output_$$\"\n \n if govulncheck ./... > \"$GOVULN_OUTPUT\" 2>&1; then\n report_security \"PASS\" \"govulncheck completed - no vulnerabilities found\"\n else\n report_security \"ERROR\" \"govulncheck found vulnerabilities in Go dependencies\"\n \n # Count vulnerabilities\n GO_VULNS=$(grep -c 'Vulnerability' \"$GOVULN_OUTPUT\" 2>/dev/null || echo \"0\")\n if [ \"$GO_VULNS\" -gt 0 ]; then\n echo \" ๐ Found $GO_VULNS Go vulnerabilities\" >&2\n TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + GO_VULNS))\n fi\n fi\n \n rm -f \"$GOVULN_OUTPUT\"\n else\n report_security \"WARNING\" \"govulncheck not available - install with 'go install golang.org/x/vuln/cmd/govulncheck@latest'\"\n fi\n fi\n \n # 5. PHP Security Scanning\n if [[ \"$PACKAGE_MANAGER\" == \"composer\" ]]; then\n echo \"๐ PHP security scanning...\" >&2\n \n if command -v composer &> /dev/null; then\n echo \" ๐ Running composer audit...\" >&2\n \n COMPOSER_AUDIT_OUTPUT=\"/tmp/composer_audit_$$\"\n \n if composer audit > \"$COMPOSER_AUDIT_OUTPUT\" 2>&1; then\n report_security \"PASS\" \"Composer audit completed - no vulnerabilities found\"\n else\n report_security \"ERROR\" \"Composer audit found vulnerabilities in PHP dependencies\"\n \n # Count vulnerabilities\n PHP_VULNS=$(grep -c 'vulnerability' \"$COMPOSER_AUDIT_OUTPUT\" 2>/dev/null || echo \"0\")\n if [ \"$PHP_VULNS\" -gt 0 ]; then\n echo \" ๐ Found $PHP_VULNS PHP vulnerabilities\" >&2\n TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + PHP_VULNS))\n fi\n fi\n \n rm -f \"$COMPOSER_AUDIT_OUTPUT\"\n else\n report_security \"WARNING\" \"Composer not available - cannot perform PHP security scan\"\n fi\n fi\n \n # 6. License Compliance Check\n echo \"๐ License compliance checking...\" >&2\n \n # Basic license check for Node.js projects\n if [[ \"$PACKAGE_MANAGER\" == \"npm\" ]] && command -v npx &> /dev/null; then\n if npx license-checker --summary >/dev/null 2>&1; then\n LICENSE_SUMMARY=$(npx license-checker --summary 2>/dev/null | head -10)\n echo \" ๐ License summary available\" >&2\n else\n report_security \"INFO\" \"license-checker not available for license compliance\"\n fi\n fi\n \n # 7. Generate Security Report\n echo \"\" >&2\n echo \"๐ Security Scan Summary:\" >&2\n echo \"=========================\" >&2\n echo \" ๐ File: $FILE_NAME\" >&2\n echo \" ๐ง Package Manager: $PACKAGE_MANAGER\" >&2\n echo \" ๐ Language: $LANGUAGE\" >&2\n echo \" ๐ Total Vulnerabilities: $TOTAL_VULNERABILITIES\" >&2\n \n if [ \"$CRITICAL_SEVERITY\" -gt 0 ]; then\n echo \" ๐จ Critical: $CRITICAL_SEVERITY\" >&2\n fi\n \n if [ \"$HIGH_SEVERITY\" -gt 0 ]; then\n echo \" ๐ด High: $HIGH_SEVERITY\" >&2\n fi\n \n if [ \"$MEDIUM_SEVERITY\" -gt 0 ]; then\n echo \" ๐ก Medium: $MEDIUM_SEVERITY\" >&2\n fi\n \n if [ \"$LOW_SEVERITY\" -gt 0 ]; then\n echo \" ๐ข Low: $LOW_SEVERITY\" >&2\n fi\n \n echo \" โ ๏ธ Warnings: $WARNINGS\" >&2\n echo \" โ Errors: $ERRORS\" >&2\n \n # Security status assessment\n if [ \"$CRITICAL_SEVERITY\" -gt 0 ]; then\n echo \" ๐จ Status: CRITICAL - Immediate action required\" >&2\n elif [ \"$HIGH_SEVERITY\" -gt 0 ]; then\n echo \" ๐ด Status: HIGH RISK - Update dependencies soon\" >&2\n elif [ \"$MEDIUM_SEVERITY\" -gt 0 ]; then\n echo \" ๐ก Status: MODERATE RISK - Plan updates\" >&2\n elif [ \"$LOW_SEVERITY\" -gt 0 ]; then\n echo \" ๐ข Status: LOW RISK - Monitor and update when convenient\" >&2\n elif [ \"$TOTAL_VULNERABILITIES\" -eq 0 ] && [ \"$ERRORS\" -eq 0 ]; then\n echo \" โ
Status: SECURE - No known vulnerabilities\" >&2\n else\n echo \" โ ๏ธ Status: UNKNOWN - Scan completed with issues\" >&2\n fi\n \n echo \"\" >&2\n echo \"๐ก Security Best Practices:\" >&2\n echo \" โข Run security scans regularly (weekly/monthly)\" >&2\n echo \" โข Keep dependencies up to date\" >&2\n echo \" โข Use dependency pinning for critical applications\" >&2\n echo \" โข Review security advisories for your dependencies\" >&2\n echo \" โข Consider using automated dependency update tools\" >&2\n echo \" โข Implement security scanning in CI/CD pipelines\" >&2\n \n # Exit with error if critical or high severity vulnerabilities found\n if [ \"$CRITICAL_SEVERITY\" -gt 0 ] || [ \"$HIGH_SEVERITY\" -gt 0 ]; then\n echo \"โ ๏ธ Security scan completed with high-priority vulnerabilities\" >&2\n exit 1\n fi\n \nelse\n # Not a package file, exit silently\n exit 0\nfi\n\nexit 0"
}.claude/hooks/~/.claude/hooks/{
"hooks": {
"postToolUse": {
"script": "./.claude/hooks/package-vulnerability-scanner.sh",
"matchers": [
"write",
"edit"
]
}
}
}#!/usr/bin/env bash
# Read the tool input from stdin
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
if [ -z "$FILE_PATH" ]; then
exit 0
fi
# Check if this is a dependency or package file
if [[ "$FILE_PATH" == *package.json ]] || [[ "$FILE_PATH" == *requirements.txt ]] || [[ "$FILE_PATH" == *Pipfile ]] || [[ "$FILE_PATH" == *Gemfile ]] || [[ "$FILE_PATH" == *go.mod ]] || [[ "$FILE_PATH" == *yarn.lock ]] || [[ "$FILE_PATH" == *package-lock.json ]] || [[ "$FILE_PATH" == *composer.json ]]; then
echo "๐ Package Vulnerability Scanner for: $(basename "$FILE_PATH")" >&2
# Initialize security counters
TOTAL_VULNERABILITIES=0
HIGH_SEVERITY=0
MEDIUM_SEVERITY=0
LOW_SEVERITY=0
CRITICAL_SEVERITY=0
FIXABLE_VULNERABILITIES=0
ERRORS=0
WARNINGS=0
# Function to report security findings
report_security() {
local level="$1"
local message="$2"
case "$level" in
"CRITICAL")
echo "๐จ CRITICAL: $message" >&2
ERRORS=$((ERRORS + 1))
;;
"ERROR")
echo "โ ERROR: $message" >&2
ERRORS=$((ERRORS + 1))
;;
"WARNING")
echo "โ ๏ธ WARNING: $message" >&2
WARNINGS=$((WARNINGS + 1))
;;
"INFO")
echo "โน๏ธ INFO: $message" >&2
;;
"PASS")
echo "โ
PASS: $message" >&2
;;
esac
}
# Detect package manager and language
PACKAGE_MANAGER=""
LANGUAGE=""
SCAN_COMMAND=""
FILE_NAME=$(basename "$FILE_PATH")
FILE_DIR=$(dirname "$FILE_PATH")
echo "๐ Analyzing package file: $FILE_NAME" >&2
# Determine package manager and language
case "$FILE_NAME" in
"package.json")
PACKAGE_MANAGER="npm"
LANGUAGE="Node.js"
;;
"yarn.lock")
PACKAGE_MANAGER="yarn"
LANGUAGE="Node.js"
;;
"package-lock.json")
PACKAGE_MANAGER="npm"
LANGUAGE="Node.js"
;;
"requirements.txt")
PACKAGE_MANAGER="pip"
LANGUAGE="Python"
;;
"Pipfile")
PACKAGE_MANAGER="pipenv"
LANGUAGE="Python"
;;
"Gemfile")
PACKAGE_MANAGER="bundler"
LANGUAGE="Ruby"
;;
"go.mod")
PACKAGE_MANAGER="go"
LANGUAGE="Go"
;;
"composer.json")
PACKAGE_MANAGER="composer"
LANGUAGE="PHP"
;;
*)
report_security "WARNING" "Unknown package file type: $FILE_NAME"
exit 0
;;
esac
echo " ๐ง Package Manager: $PACKAGE_MANAGER" >&2
echo " ๐ Language: $LANGUAGE" >&2
# 1. Node.js Security Scanning
if [[ "$PACKAGE_MANAGER" == "npm" ]] || [[ "$PACKAGE_MANAGER" == "yarn" ]]; then
echo "๐ฆ Node.js security scanning..." >&2
# Check if npm is available
if command -v npm &> /dev/null; then
echo " ๐ Running npm audit..." >&2
NPM_AUDIT_OUTPUT="/tmp/npm_audit_$$"
# Run npm audit with JSON output
if npm audit --json > "$NPM_AUDIT_OUTPUT" 2>&1; then
# Parse npm audit results
if command -v jq &> /dev/null; then
AUDIT_SUMMARY=$(jq -r '.metadata.vulnerabilities' "$NPM_AUDIT_OUTPUT" 2>/dev/null || echo '{}')
if [ "$AUDIT_SUMMARY" != "{}" ] && [ "$AUDIT_SUMMARY" != "null" ]; then
# Extract vulnerability counts
CRITICAL_COUNT=$(echo "$AUDIT_SUMMARY" | jq -r '.critical // 0')
HIGH_COUNT=$(echo "$AUDIT_SUMMARY" | jq -r '.high // 0')
MODERATE_COUNT=$(echo "$AUDIT_SUMMARY" | jq -r '.moderate // 0')
LOW_COUNT=$(echo "$AUDIT_SUMMARY" | jq -r '.low // 0')
TOTAL_VULNERABILITIES=$((CRITICAL_COUNT + HIGH_COUNT + MODERATE_COUNT + LOW_COUNT))
CRITICAL_SEVERITY=$CRITICAL_COUNT
HIGH_SEVERITY=$HIGH_COUNT
MEDIUM_SEVERITY=$MODERATE_COUNT
LOW_SEVERITY=$LOW_COUNT
echo " ๐ Vulnerability summary:" >&2
echo " ๐จ Critical: $CRITICAL_COUNT" >&2
echo " ๐ด High: $HIGH_COUNT" >&2
echo " ๐ก Moderate: $MODERATE_COUNT" >&2
echo " ๐ข Low: $LOW_COUNT" >&2
if [ "$CRITICAL_COUNT" -gt 0 ]; then
report_security "CRITICAL" "$CRITICAL_COUNT critical vulnerabilities found"
fi
if [ "$HIGH_COUNT" -gt 0 ]; then
report_security "ERROR" "$HIGH_COUNT high severity vulnerabilities found"
fi
if [ "$MODERATE_COUNT" -gt 0 ]; then
report_security "WARNING" "$MODERATE_COUNT moderate severity vulnerabilities found"
fi
# Show top vulnerabilities
TOP_VULNS=$(jq -r '.vulnerabilities | to_entries | .[0:3] | .[] | " โข " + .key + " (" + .value.severity + ")"' "$NPM_AUDIT_OUTPUT" 2>/dev/null || echo "")
if [ -n "$TOP_VULNS" ]; then
echo " ๐ฏ Top vulnerabilities:" >&2
echo "$TOP_VULNS" >&2
fi
else
report_security "PASS" "No vulnerabilities found in npm dependencies"
fi
else
report_security "WARNING" "jq not available - limited vulnerability parsing"
fi
else
# npm audit failed, check if it's due to vulnerabilities
AUDIT_EXIT_CODE=$?
if [ $AUDIT_EXIT_CODE -eq 1 ]; then
# Exit code 1 means vulnerabilities found
report_security "ERROR" "npm audit found vulnerabilities (exit code 1)"
# Try to extract basic info
VULN_COUNT=$(grep -o 'vulnerabilities' "$NPM_AUDIT_OUTPUT" 2>/dev/null | wc -l || echo "0")
if [ "$VULN_COUNT" -gt 0 ]; then
echo " โ ๏ธ Estimated vulnerabilities: $VULN_COUNT" >&2
fi
else
report_security "ERROR" "npm audit failed with exit code $AUDIT_EXIT_CODE"
fi
fi
rm -f "$NPM_AUDIT_OUTPUT"
# Check for yarn if available
if [[ "$PACKAGE_MANAGER" == "yarn" ]] && command -v yarn &> /dev/null; then
echo " ๐งถ Running yarn audit..." >&2
YARN_AUDIT_OUTPUT="/tmp/yarn_audit_$$"
if yarn audit --json > "$YARN_AUDIT_OUTPUT" 2>&1; then
report_security "PASS" "Yarn audit completed successfully"
else
report_security "WARNING" "Yarn audit found issues or failed"
fi
rm -f "$YARN_AUDIT_OUTPUT"
fi
else
report_security "WARNING" "npm not available - cannot perform Node.js security scan"
fi
fi
# 2. Python Security Scanning
if [[ "$PACKAGE_MANAGER" == "pip" ]] || [[ "$PACKAGE_MANAGER" == "pipenv" ]]; then
echo "๐ Python security scanning..." >&2
# Check for safety tool
if command -v safety &> /dev/null; then
echo " ๐ Running safety check..." >&2
SAFETY_OUTPUT="/tmp/safety_output_$$"
if safety check --json > "$SAFETY_OUTPUT" 2>&1; then
report_security "PASS" "Safety check completed - no vulnerabilities found"
else
# Safety found vulnerabilities
SAFETY_EXIT_CODE=$?
if [ $SAFETY_EXIT_CODE -eq 64 ]; then
# Exit code 64 means vulnerabilities found
report_security "ERROR" "Safety found vulnerabilities in Python dependencies"
# Try to parse vulnerabilities
if command -v jq &> /dev/null && [ -f "$SAFETY_OUTPUT" ]; then
VULN_COUNT=$(jq length "$SAFETY_OUTPUT" 2>/dev/null || echo "0")
if [ "$VULN_COUNT" -gt 0 ]; then
echo " ๐ Found $VULN_COUNT Python vulnerabilities" >&2
TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + VULN_COUNT))
# Show first few vulnerabilities
jq -r '.[0:3] | .[] | " โข " + .package + " (" + .vulnerability_id + ")"' "$SAFETY_OUTPUT" 2>/dev/null | while read line; do
echo "$line" >&2
done
fi
fi
else
report_security "WARNING" "Safety check failed with exit code $SAFETY_EXIT_CODE"
fi
fi
rm -f "$SAFETY_OUTPUT"
elif command -v pip &> /dev/null; then
echo " ๐ Safety not available, using pip-audit if available..." >&2
if command -v pip-audit &> /dev/null; then
PIP_AUDIT_OUTPUT="/tmp/pip_audit_$$"
if pip-audit --format=json > "$PIP_AUDIT_OUTPUT" 2>&1; then
report_security "PASS" "pip-audit completed - no vulnerabilities found"
else
report_security "ERROR" "pip-audit found vulnerabilities in Python dependencies"
fi
rm -f "$PIP_AUDIT_OUTPUT"
else
report_security "WARNING" "No Python security tools available (safety, pip-audit)"
fi
else
report_security "WARNING" "Python/pip not available - cannot perform Python security scan"
fi
fi
# 3. Ruby Security Scanning
if [[ "$PACKAGE_MANAGER" == "bundler" ]]; then
echo "๐ Ruby security scanning..." >&2
if command -v bundler-audit &> /dev/null; then
echo " ๐ Running bundler-audit..." >&2
BUNDLER_AUDIT_OUTPUT="/tmp/bundler_audit_$$"
if bundler-audit check > "$BUNDLER_AUDIT_OUTPUT" 2>&1; then
report_security "PASS" "bundler-audit completed - no vulnerabilities found"
else
report_security "ERROR" "bundler-audit found vulnerabilities in Ruby dependencies"
# Count vulnerabilities
RUBY_VULNS=$(grep -c 'Vulnerability found' "$BUNDLER_AUDIT_OUTPUT" 2>/dev/null || echo "0")
if [ "$RUBY_VULNS" -gt 0 ]; then
echo " ๐ Found $RUBY_VULNS Ruby vulnerabilities" >&2
TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + RUBY_VULNS))
fi
fi
rm -f "$BUNDLER_AUDIT_OUTPUT"
else
report_security "WARNING" "bundler-audit not available - install with 'gem install bundler-audit'"
fi
fi
# 4. Go Security Scanning
if [[ "$PACKAGE_MANAGER" == "go" ]]; then
echo "๐น Go security scanning..." >&2
if command -v govulncheck &> /dev/null; then
echo " ๐ Running govulncheck..." >&2
GOVULN_OUTPUT="/tmp/govuln_output_$$"
if govulncheck ./... > "$GOVULN_OUTPUT" 2>&1; then
report_security "PASS" "govulncheck completed - no vulnerabilities found"
else
report_security "ERROR" "govulncheck found vulnerabilities in Go dependencies"
# Count vulnerabilities
GO_VULNS=$(grep -c 'Vulnerability' "$GOVULN_OUTPUT" 2>/dev/null || echo "0")
if [ "$GO_VULNS" -gt 0 ]; then
echo " ๐ Found $GO_VULNS Go vulnerabilities" >&2
TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + GO_VULNS))
fi
fi
rm -f "$GOVULN_OUTPUT"
else
report_security "WARNING" "govulncheck not available - install with 'go install golang.org/x/vuln/cmd/govulncheck@latest'"
fi
fi
# 5. PHP Security Scanning
if [[ "$PACKAGE_MANAGER" == "composer" ]]; then
echo "๐ PHP security scanning..." >&2
if command -v composer &> /dev/null; then
echo " ๐ Running composer audit..." >&2
COMPOSER_AUDIT_OUTPUT="/tmp/composer_audit_$$"
if composer audit > "$COMPOSER_AUDIT_OUTPUT" 2>&1; then
report_security "PASS" "Composer audit completed - no vulnerabilities found"
else
report_security "ERROR" "Composer audit found vulnerabilities in PHP dependencies"
# Count vulnerabilities
PHP_VULNS=$(grep -c 'vulnerability' "$COMPOSER_AUDIT_OUTPUT" 2>/dev/null || echo "0")
if [ "$PHP_VULNS" -gt 0 ]; then
echo " ๐ Found $PHP_VULNS PHP vulnerabilities" >&2
TOTAL_VULNERABILITIES=$((TOTAL_VULNERABILITIES + PHP_VULNS))
fi
fi
rm -f "$COMPOSER_AUDIT_OUTPUT"
else
report_security "WARNING" "Composer not available - cannot perform PHP security scan"
fi
fi
# 6. License Compliance Check
echo "๐ License compliance checking..." >&2
# Basic license check for Node.js projects
if [[ "$PACKAGE_MANAGER" == "npm" ]] && command -v npx &> /dev/null; then
if npx license-checker --summary >/dev/null 2>&1; then
LICENSE_SUMMARY=$(npx license-checker --summary 2>/dev/null | head -10)
echo " ๐ License summary available" >&2
else
report_security "INFO" "license-checker not available for license compliance"
fi
fi
# 7. Generate Security Report
echo "" >&2
echo "๐ Security Scan Summary:" >&2
echo "=========================" >&2
echo " ๐ File: $FILE_NAME" >&2
echo " ๐ง Package Manager: $PACKAGE_MANAGER" >&2
echo " ๐ Language: $LANGUAGE" >&2
echo " ๐ Total Vulnerabilities: $TOTAL_VULNERABILITIES" >&2
if [ "$CRITICAL_SEVERITY" -gt 0 ]; then
echo " ๐จ Critical: $CRITICAL_SEVERITY" >&2
fi
if [ "$HIGH_SEVERITY" -gt 0 ]; then
echo " ๐ด High: $HIGH_SEVERITY" >&2
fi
if [ "$MEDIUM_SEVERITY" -gt 0 ]; then
echo " ๐ก Medium: $MEDIUM_SEVERITY" >&2
fi
if [ "$LOW_SEVERITY" -gt 0 ]; then
echo " ๐ข Low: $LOW_SEVERITY" >&2
fi
echo " โ ๏ธ Warnings: $WARNINGS" >&2
echo " โ Errors: $ERRORS" >&2
# Security status assessment
if [ "$CRITICAL_SEVERITY" -gt 0 ]; then
echo " ๐จ Status: CRITICAL - Immediate action required" >&2
elif [ "$HIGH_SEVERITY" -gt 0 ]; then
echo " ๐ด Status: HIGH RISK - Update dependencies soon" >&2
elif [ "$MEDIUM_SEVERITY" -gt 0 ]; then
echo " ๐ก Status: MODERATE RISK - Plan updates" >&2
elif [ "$LOW_SEVERITY" -gt 0 ]; then
echo " ๐ข Status: LOW RISK - Monitor and update when convenient" >&2
elif [ "$TOTAL_VULNERABILITIES" -eq 0 ] && [ "$ERRORS" -eq 0 ]; then
echo " โ
Status: SECURE - No known vulnerabilities" >&2
else
echo " โ ๏ธ Status: UNKNOWN - Scan completed with issues" >&2
fi
echo "" >&2
echo "๐ก Security Best Practices:" >&2
echo " โข Run security scans regularly (weekly/monthly)" >&2
echo " โข Keep dependencies up to date" >&2
echo " โข Use dependency pinning for critical applications" >&2
echo " โข Review security advisories for your dependencies" >&2
echo " โข Consider using automated dependency update tools" >&2
echo " โข Implement security scanning in CI/CD pipelines" >&2
# Exit with error if critical or high severity vulnerabilities found
if [ "$CRITICAL_SEVERITY" -gt 0 ] || [ "$HIGH_SEVERITY" -gt 0 ]; then
echo "โ ๏ธ Security scan completed with high-priority vulnerabilities" >&2
exit 1
fi
else
# Not a package file, exit silently
exit 0
fi
exit 0npm audit exits with code 1 blocking hook
Hook handles exit code 1 as vulnerabilities found, not failure. To prevent blocking: wrap in `|| true` or check `$AUDIT_EXIT_CODE`: `if [ $AUDIT_EXIT_CODE -eq 1 ]; then report_security "ERROR" ...`
jq not available causes JSON parsing errors
Install jq: `brew install jq` (macOS), `apt-get install jq` (Ubuntu), or `npm install -g jq`. Hook falls back gracefully: `jq -r '.metadata.vulnerabilities' ... 2>/dev/null || echo '{}'`
Python safety check requires paid API key
Free tier has 30-day delay for vulnerability data. Use pip-audit as fallback: `pip install pip-audit`, hook auto-detects: `if command -v pip-audit &> /dev/null; then pip-audit --format=json`
Hook scans every package.json edit too slow
Add hash check to skip unchanged files: `FILE_HASH=$(md5sum "$FILE_PATH")` and cache. Or limit to root only: `if [[ "$FILE_PATH" != ./package.json ]]; then exit 0; fi`
Cannot distinguish severity levels in output
Hook provides structured counts: CRITICAL_SEVERITY, HIGH_SEVERITY, MEDIUM_SEVERITY, LOW_SEVERITY. Parse from npm audit JSON: `CRITICAL_COUNT=$(echo "$AUDIT_SUMMARY" | jq -r '.critical // 0')`
Loading reviews...
Join our community of Claude power users. No spam, unsubscribe anytime.
Automated accessibility testing and compliance checking for web applications following WCAG guidelines
Automatically generates or updates API documentation when endpoint files are modified
Automatically formats code files after Claude writes or edits them using Prettier, Black, or other formatters