MCPJam / MCPJam/inspector

OAuth debugger SSRF guard blocks intranet MCP servers on CGNAT (100.64/10) — no opt-out for self-hosted use

Open
#3,694 2 comments 0 reactions 0 assignees View on GitHub
bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.