-
Notifications
You must be signed in to change notification settings - Fork 3
257 lines (228 loc) · 9.3 KB
/
mcp-lockdown-mode-proof.yml
File metadata and controls
257 lines (228 loc) · 9.3 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
name: MCP Lockdown Mode Bug Proof
# This workflow demonstrates that lockdown mode is broken when using
# GITHUB_TOKEN with read-all permissions on public repositories.
# See bug.md for full details.
on:
workflow_dispatch:
permissions:
contents: read
jobs:
lockdown-bug-proof:
name: Prove lockdown blocks all content with GITHUB_TOKEN
runs-on: ubuntu-latest
steps:
- name: Checkout this repository
uses: actions/checkout@v4
- name: Clone github-mcp-server
run: git clone --depth 1 https://github.com/github/github-mcp-server.git mcp-server
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: mcp-server/go.mod
- name: Build MCP server
working-directory: mcp-server
run: go build -v -o ../github-mcp-server ./cmd/github-mcp-server
- name: Print server version
run: ./github-mcp-server --version
- name: Start MCP server in HTTP mode with lockdown enabled
env:
GITHUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
./github-mcp-server http \
--port 8082 \
--lockdown-mode \
--log-file server.log &
SERVER_PID=$!
echo "SERVER_PID=$SERVER_PID" >> "$GITHUB_ENV"
# Wait for the server to be ready
echo "Waiting for server to start..."
for i in $(seq 1 30); do
if curl -s -o /dev/null -w "%{http_code}" http://localhost:8082/ | grep -qE '2[0-9]{2}|405'; then
echo "Server is ready after ${i}s"
break
fi
sleep 1
done
- name: "Test 1: Initialize MCP session"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "=== Sending MCP initialize request ==="
INIT_RESPONSE=$(curl -s -X POST http://localhost:8082/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "lockdown-bug-proof",
"version": "1.0.0"
}
}
}')
echo "Initialize response:"
echo "$INIT_RESPONSE" | head -c 2000
echo ""
# Extract session ID from Mcp-Session header if present
SESSION_ID=$(curl -s -D - -o /dev/null -X POST http://localhost:8082/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": {
"name": "lockdown-bug-proof",
"version": "1.0.0"
}
}
}' | grep -i 'mcp-session' | tr -d '\r' | awk '{print $2}')
echo "Session ID: $SESSION_ID"
echo "SESSION_ID=$SESSION_ID" >> "$GITHUB_ENV"
- name: "Test 2: Call issue_read on admin content in a public repo (desired: results returned, actual: lockdown blocks)"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "=== Calling issue_read (method: get) on a public repo issue created by an admin ==="
echo "This targets github/github-mcp-server#1 (a public repo)."
echo "With GITHUB_TOKEN read-all, the collaborators GraphQL query returns"
echo "empty results, so lockdown will treat ALL authors as unsafe."
echo ""
TOOL_RESPONSE=$(curl -s -X POST http://localhost:8082/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-MCP-Lockdown: true" \
${SESSION_ID:+-H "Mcp-Session: $SESSION_ID"} \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "issue_read",
"arguments": {
"method": "get",
"owner": "githubnext",
"repo": "gh-aw-test",
"issue_number": 44
}
}
}')
echo "issue_read response:"
echo "$TOOL_RESPONSE" | head -c 5000
echo ""
# Check if the response contains the lockdown error message
if echo "$TOOL_RESPONSE" | grep -qi "restricted by lockdown"; then
echo ""
echo "********************************************"
echo "* BUG CONFIRMED: Lockdown mode blocked *"
echo "* access even though the issue author may *"
echo "* be a legitimate collaborator. The *"
echo "* GITHUB_TOKEN cannot enumerate *"
echo "* collaborators via the GraphQL API. *"
echo "********************************************"
elif echo "$TOOL_RESPONSE" | grep -qi "error"; then
echo ""
echo "Got an error (may be auth/API related):"
echo "$TOOL_RESPONSE" | head -c 2000
else
echo ""
echo "Unexpectedly succeeded — lockdown did not block. Check response above."
fi
- name: "Test 3: Call issue_read get_comments on admin content in a public repo (desired: returns admin comments, actual: filtered to zero)"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "=== Calling issue_read (method: get_comments) on a public repo ==="
echo "Even if issue_read get passes, comment filtering should drop ALL"
echo "comments because no author appears to have push access."
echo ""
COMMENTS_RESPONSE=$(curl -s -X POST http://localhost:8082/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "X-MCP-Lockdown: true" \
${SESSION_ID:+-H "Mcp-Session: $SESSION_ID"} \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "issue_read",
"arguments": {
"method": "get_comments",
"owner": "githubnext",
"repo": "gh-aw-test",
"issue_number": 44
}
}
}')
echo "issue_read get_comments response:"
echo "$COMMENTS_RESPONSE" | head -c 5000
echo ""
if echo "$COMMENTS_RESPONSE" | grep -qi "restricted by lockdown"; then
echo ""
echo "BUG CONFIRMED: Comments blocked by lockdown."
elif echo "$COMMENTS_RESPONSE" | grep -q '\[\]'; then
echo ""
echo "BUG CONFIRMED: Comments returned empty array — all filtered out."
else
echo "Check the response above manually."
fi
- name: "Test 4: Same request WITHOUT lockdown (should succeed)"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "=== Calling issue_read WITHOUT lockdown header (control test) ==="
echo "This confirms the token itself works fine for reading issues."
echo ""
CONTROL_RESPONSE=$(curl -s -X POST http://localhost:8082/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $GITHUB_TOKEN" \
${SESSION_ID:+-H "Mcp-Session: $SESSION_ID"} \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "issue_read",
"arguments": {
"method": "get",
"owner": "githubnext",
"repo": "gh-aw-test",
"issue_number": 44
}
}
}')
echo "issue_read (no lockdown) response:"
echo "$CONTROL_RESPONSE" | head -c 5000
echo ""
if echo "$CONTROL_RESPONSE" | grep -qi "restricted by lockdown"; then
echo "UNEXPECTED: Lockdown blocked even without the header."
elif echo "$CONTROL_RESPONSE" | grep -qi "error"; then
echo "Got an error (may be auth/API):"
echo "$CONTROL_RESPONSE" | head -c 2000
else
echo "SUCCESS: Issue retrieved without lockdown — token works fine."
fi
- name: Print server logs
if: always()
run: |
echo "=== Server log output ==="
cat server.log 2>/dev/null || echo "No server log file found."
- name: Stop server
if: always()
run: |
if [ -n "$SERVER_PID" ]; then
kill "$SERVER_PID" 2>/dev/null || true
fi