Configuration & Environment
An MCP OAuth proxy validates the `redirect_uri` parameter using `.startswith` / `.endswith` / regex / glob matching instead of exact string equality — letting a maliciously-registered client choose a `redirect_uri` that passes validation but redirects to attacker infrastructure.
OAuth requires `redirect_uri` to be validated by exact string match against the registered URI. Any looser matcher creates a bypass: `startswith("https://app.example.com/")` is satisfied by `https://app.example.com.attacker.example`, regex with `.*` is satisfied by anything matching the prefix. The official MCP security best practices explicitly require exact match.
OAuth-proxy MCP servers receive registered `redirect_uri` values from MCP clients (RFC 7591 dynamic client registration) and need to validate them at every authorize request. Developers reach for `startswith` because it accepts trailing query-string parameters or paths — but the looseness lets an attacker steal the auth code via a different host that happens to share a prefix.
@app.get("/authorize") |
def authorize(redirect_uri: str) -> dict: |
if not redirect_uri.startswith("https://app.example.com/"): |
return {"error": "invalid_redirect_uri"} |
return {"ok": True} |
REGISTERED_URIS = { |
"https://app.example.com/callback", |
"https://app.example.com/cb-mobile", |
} |
@app.get("/authorize") |
def authorize(redirect_uri: str) -> dict: |
if redirect_uri not in REGISTERED_URIS: |
return {"error": "invalid_redirect_uri"} |
return {"ok": True} |
Per-occurrence detection in MCP-server-context files. Fires on `redirect_uri.startswith(...)` / `.endswith(...)` (Python) / `redirectUri.startsWith(...)` / `.endsWith(...)` (JS), `re.match`/`re.search`/`re.fullmatch` with `*` in the pattern, JS `regex.test(redirectUri)` with wildcard, or `fnmatch(redirect_uri, ...)`. The canonical safe patterns are `==`/`===` against the registered URI string or set/list membership against a registered URI set. `urlparse` component-by-component compare is accepted only when every component (scheme, host, port, path, query) is checked against a registered URI — partial-component comparison fails the spec's exact-match requirement.
See the full threat catalog for every documented detection.
MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.
Scan now