forked from FlorianBruniaux/claude-code-ultimate-guide
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmcp-config-integrity.sh
More file actions
executable file
·118 lines (101 loc) · 4.61 KB
/
mcp-config-integrity.sh
File metadata and controls
executable file
·118 lines (101 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/bin/bash
# =============================================================================
# MCP Config Integrity Hook
# =============================================================================
# Event: SessionStart (runs when Claude Code session begins)
# Purpose: Verify MCP configuration has not been tampered with
#
# This hook addresses CVE-2025-54135 and CVE-2025-54136 by:
# - Computing hash of ~/.claude/mcp.json
# - Comparing against stored baseline
# - Alerting on unauthorized modifications
# - Checking project-level .mcp.json for suspicious content
#
# Installation:
# Add to .claude/settings.json:
# {
# "hooks": {
# "SessionStart": [
# "bash examples/hooks/bash/mcp-config-integrity.sh"
# ]
# }
# }
#
# Initial setup (run once to create baseline):
# sha256sum ~/.claude/mcp.json > ~/.claude/.mcp-baseline.sha256
#
# Exit codes:
# 0 = allow (config unchanged or no baseline)
# Non-zero outputs systemMessage warnings
#
# References:
# - CVE-2025-54135: RCE in Cursor via prompt injection rewriting mcp.json
# - CVE-2025-54136: Persistent team backdoor via post-approval config tampering
# =============================================================================
set -euo pipefail
# Configuration paths
MCP_CONFIG="${HOME}/.claude/mcp.json"
MCP_BASELINE="${HOME}/.claude/.mcp-baseline.sha256"
PROJECT_MCP=".mcp.json"
WARNINGS=()
# === GLOBAL MCP CONFIG CHECK ===
if [[ -f "$MCP_CONFIG" ]]; then
# Check if baseline exists
if [[ -f "$MCP_BASELINE" ]]; then
# Compute current hash
CURRENT_HASH=$(sha256sum "$MCP_CONFIG" 2>/dev/null | awk '{print $1}')
BASELINE_HASH=$(awk '{print $1}' "$MCP_BASELINE" 2>/dev/null || echo "")
if [[ -n "$CURRENT_HASH" && -n "$BASELINE_HASH" && "$CURRENT_HASH" != "$BASELINE_HASH" ]]; then
WARNINGS+=("MCP config modified since baseline was created. Review ~/.claude/mcp.json for unauthorized changes. Run 'sha256sum ~/.claude/mcp.json > ~/.claude/.mcp-baseline.sha256' to update baseline if changes are legitimate.")
fi
else
# No baseline - suggest creating one
WARNINGS+=("No MCP config baseline found. Consider running: sha256sum ~/.claude/mcp.json > ~/.claude/.mcp-baseline.sha256")
fi
# === CHECK FOR SUSPICIOUS MCP SERVERS ===
# Look for known risky patterns
MCP_CONTENT=$(cat "$MCP_CONFIG" 2>/dev/null || echo "{}")
# Check for dangerous flags
if echo "$MCP_CONTENT" | grep -qiE '"--dangerous|"--allow-write|"--no-sandbox'; then
WARNINGS+=("MCP config contains dangerous flags (--dangerous, --allow-write, or --no-sandbox). Review carefully.")
fi
# Check for unpinned versions (using @latest or no version)
if echo "$MCP_CONTENT" | grep -qE '"[^"]*@latest"|"npx"[^}]*"-y"[^}]*"[^@"]+\"'; then
WARNINGS+=("MCP config may contain unpinned versions (@latest or missing version). Pin to specific versions for security.")
fi
# Check for suspicious environment variables
if echo "$MCP_CONTENT" | grep -qiE '"env"[^}]*"(PASSWORD|SECRET|TOKEN|API_KEY|PRIVATE_KEY)"'; then
WARNINGS+=("MCP config contains potentially sensitive environment variables. Ensure these are not hardcoded secrets.")
fi
# Check for external URLs in commands
if echo "$MCP_CONTENT" | grep -qE 'https?://[^"]+' | grep -vE 'npm|github|registry'; then
WARNINGS+=("MCP config references external URLs. Verify these are trusted sources.")
fi
fi
# === PROJECT-LEVEL MCP CONFIG CHECK ===
if [[ -f "$PROJECT_MCP" ]]; then
PROJECT_MCP_CONTENT=$(cat "$PROJECT_MCP" 2>/dev/null || echo "{}")
# Check for dangerous flags in project config
if echo "$PROJECT_MCP_CONTENT" | grep -qiE '"--dangerous|"--allow-write|"--no-sandbox'; then
WARNINGS+=("Project .mcp.json contains dangerous flags. This could be a supply chain attack.")
fi
# Check for shell injection patterns
if echo "$PROJECT_MCP_CONTENT" | grep -qE '\$\(|`[^`]+`|&&|\|\|'; then
WARNINGS+=("Project .mcp.json contains shell metacharacters. Review for command injection.")
fi
# Check for base64-encoded content
if echo "$PROJECT_MCP_CONTENT" | grep -qE '[A-Za-z0-9+/]{40,}={0,2}'; then
WARNINGS+=("Project .mcp.json contains base64-like content. This could hide malicious payloads.")
fi
fi
# === OUTPUT WARNINGS ===
if [[ ${#WARNINGS[@]} -gt 0 ]]; then
WARNING_MSG=""
for warning in "${WARNINGS[@]}"; do
WARNING_MSG="${WARNING_MSG}⚠️ ${warning} "
done
# Output as systemMessage
echo "{\"systemMessage\": \"MCP INTEGRITY CHECK: ${WARNING_MSG}\"}"
fi
# Always exit 0 (warn, don't block session start)
exit 0