OAuth debugger SSRF guard blocks intranet MCP servers on CGNAT (100.64/10) — no opt-out for self-hosted use
- Dominant language
- TypeScript
- Stars
- 2.2k
- Forks
- 283
- Avg merge
- 11h 47m
- Merged PRs (30d)
- 737
Description
## Summary
The OAuth debugger's backend proxy (`/api/mcp/oauth/debug/proxy`) refuses to send requests to MCP servers whose hostname resolves into `100.64.0.0/10` (CGNAT / RFC 6598 shared address space). The SSRF guard in `sdk/src/oauth/ssrf-guard.ts` classifies that range as disallowed:
```ts
if (a === 100 && b >= 64 && b <= 127) return true; // 100.64/10 CGNAT
```
Every OAuth debugger step then fails at `request_without_token` with `Backend debug proxy error: 400 Bad Request` — before any request reaches the server, so from the user's perspective a perfectly healthy server "fails OAuth" with no actionable detail.
## Why this matters
Self-hosted Inspector on a corporate network is exactly the environment where an internal MCP server lives behind a load-balancer VIP in shared address space. The server in our case returns a spec-correct `401` + `WWW-Authenticate: Bearer resource_metadata=...` challenge (verified with curl byte-for-byte against the debugger's request), and other clients (Claude Code, Open WebUI) complete the full OAuth flow against it. Only the Inspector's guarded proxy path is unable to test it.
The SSRF guard is entirely reasonable for the hosted product; for a locally-run Inspector pointed at intranet infrastructure it blocks the primary use case.
## Repro
1. Run the Inspector locally (`localhost:6274`).
2. Add an HTTP MCP server whose DNS resolves to an address in `100.64.0.0/10` (OAuth-protected, returns a standard 401 challenge).
3. Open the OAuth debugger and start the flow.
4. First step fails: `Backend debug proxy error: 400 Bad Request`; the server never receives a request.
## Ask
An explicit opt-out for self-hosted/local mode — e.g. an env var like `MCPJAM_ALLOW_PRIVATE_TARGETS=1` (or a per-server "trust this private host" toggle in the UI) that relaxes the SSRF guard for the debug proxy when the Inspector is not running in hosted mode. Even limiting the exemption to 100.64/10 + RFC 1918 while keeping loopback/link-local rules intact would cover the corporate-intranet case.
Happy to test a patch against our environment.
Contributor guide
Research direction
Start by reading sdk/src/oauth/ssrf-guard.ts and tracing the /api/mcp/oauth/debug/proxy path, then reproduce the OAuth debugger failure with an MCP server resolving to 100.64.0.0/10. Done means self-hosted/local mode can explicitly permit the requested private target while the hosted product retains its SSRF protections.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100