-
Notifications
You must be signed in to change notification settings - Fork 1
fix: get_token endpoint has no authentication — bootstrap problem #42
Description
What Exists
The MCP server exposes a get_token tool that issues a session-scoped JWT to any caller (#19). The token grants tool-level authorization for the session. Once a token is issued, all subsequent tool calls must include it.
The server binds to localhost (stdio mode or 127.0.0.1 in HTTP mode), which limits the attack surface to local processes.
What's Missing
get_token has no authentication. Any MCP client that connects to the server can call get_token and receive a valid JWT with full policy scopes. This is the classic bootstrap problem: you need auth to get auth, but the auth-dispensing endpoint is unprotected.
Attack scenario (local attacker):
- Attacker discovers the MCP server port (e.g., by scanning localhost)
- Attacker connects and calls
get_tokenbefore the legitimate Claude Code client - Attacker receives a valid JWT and can call any tool the policy allows
- When the legitimate client calls
get_token, a second token is issued (both are valid)
Mitigating factors:
- Stdio mode (default): Only the process that spawned the server has stdin/stdout access. This is secure.
- HTTP/SSE mode: Binds to localhost, so only local processes can connect. The attack window is small.
Proposed Fix
Option A: PID verification on get_token (strongest)
The server already does PID introspection for identity discovery. Extend this to get_token:
- On
get_tokencall, get the connecting client's PID viaSO_PEERCRED(Unix socket) or TCP port-to-PID mapping - Verify the PID matches the expected agent process (e.g., Claude Code binary)
- Only issue tokens to verified agent processes
This ties into #24 (identity discovery uses spoofable heuristics). A proper SO_PEERCRED implementation would solve both.
Option B: Bootstrap secret (simpler)
- On server start, generate a random bootstrap secret and write it to a file readable only by the agent's UID
get_tokenrequires the bootstrap secret as a parameter- After first successful
get_token, invalidate the bootstrap secret (one-time use)
Option C: Issue token automatically on initialize (simplest)
Instead of a separate get_token call, issue the JWT during the MCP initialize handshake and return it in the server capabilities. The client gets the token as part of connection setup — no separate unauthenticated endpoint.
Related
- feat: implement JWT-based agent authorization #19 — JWT implementation
- fix: identity discovery uses spoofable process-tree heuristics, not SO_PEERCRED #24 — Identity discovery uses spoofable heuristics
- fix: hook lifecycle has five fail-open bypass paths #27 — Fail-open bypass paths (HTTP binding)