Skip to content

fix(mcp): pin cross-origin OAuth discovered-issuer requests per-request#6092

Merged
bug-ops merged 1 commit into
mainfrom
fix/6074-mcp-oauth-cross-origin-ssrf
Jul 11, 2026
Merged

fix(mcp): pin cross-origin OAuth discovered-issuer requests per-request#6092
bug-ops merged 1 commit into
mainfrom
fix/6074-mcp-oauth-cross-origin-ssrf

Conversation

@bug-ops

@bug-ops bug-ops commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #6074

Test plan

  • cargo +nightly fmt --check — clean
  • cargo clippy --profile ci --workspace --all-targets --features "desktop,ide,server,chat,pdf,scheduler,testing" -- -D warnings — clean
  • cargo nextest run --config-file .github/nextest.toml --workspace --features "desktop,ide,server,chat,pdf,scheduler" --lib --bins — 12901 passed, 0 failed
  • RUSTFLAGS="-D warnings" RUSTDOCFLAGS="--deny rustdoc::broken_intra_doc_links" cargo doc --no-deps --workspace --features "desktop,ide,server,chat,pdf,scheduler" — clean
  • New regression tests: PinningOAuthHttpClient blocked on private/loopback cross-origin hosts, allowed on public IP literal, trusted-mode bypass verified
  • Adversarially reviewed (redirect-hop scope, TOCTOU window, host/port extraction, trusted-flag threading, test-coverage honesty) — verdict: minor, one deferred finding tracked in zeph-mcp oauth.rs: PinningOAuthHttpClient does not pin redirect-hop hosts for Follow-policy OAuth requests #6089
  • CHANGELOG.md updated under [Unreleased]

@github-actions github-actions Bot added documentation Improvements or additions to documentation rust Rust code changes bug Something isn't working size/L Large PR (201-500 lines) labels Jul 11, 2026
@bug-ops
bug-ops enabled auto-merge (squash) July 11, 2026 20:24
@bug-ops
bug-ops force-pushed the fix/6074-mcp-oauth-cross-origin-ssrf branch from eaca1ae to f4c43f8 Compare July 11, 2026 20:24
validate_oauth_metadata_urls validated OAuth-discovered endpoints
(token_endpoint, authorization_endpoint, jwks_uri, registration_endpoint)
then discarded the result. #6069 pinned the MCP server's own host via a
single resolve_to_addrs client, but per SEP-985 these endpoints may live
on a different host, which AuthorizationManager resolved independently
and unpinned — reopening the DNS-rebinding TOCTOU for cross-origin
issuers.

Add PinningOAuthHttpClient, an rmcp OAuthHttpClient implementation that
resolves, SSRF-validates, and DNS-pins every OAuth HTTP request
individually at execution time, regardless of target host. Wire it into
connect_url_oauth via OAuthState::new_with_oauth_http_client. Keep
validate_oauth_metadata_urls as a fail-fast pre-check only, since it is
no longer the security boundary.

Follow-up #6089 filed for a narrower, separate gap: Follow-policy
requests (dynamic client registration) don't pin redirect-hop hosts.
@bug-ops
bug-ops force-pushed the fix/6074-mcp-oauth-cross-origin-ssrf branch from f4c43f8 to a016191 Compare July 11, 2026 20:26
@bug-ops
bug-ops merged commit e9c785e into main Jul 11, 2026
43 checks passed
@bug-ops
bug-ops deleted the fix/6074-mcp-oauth-cross-origin-ssrf branch July 11, 2026 20:35
bug-ops added a commit that referenced this pull request Jul 11, 2026
PinningOAuthHttpClient (#6074, PR #6092) validated and DNS-pinned every
OAuth HTTP request's host, but only disabled reqwest's built-in
redirect-following for OAuthHttpRedirectPolicy::Stop requests. For
Follow (dynamic client registration is rmcp's only current caller), a
3xx response pointing at a different host had that hop resolved by
reqwest itself, independently and unpinned, reopening a
redirect-scoped DNS-rebinding TOCTOU.

build_client now disables redirects unconditionally, and execute()
follows Follow-policy redirects manually via a bounded loop
(MAX_OAUTH_REDIRECT_HOPS) that re-validates and re-pins each hop.
Sensitive headers (Authorization, Cookie, Proxy-Authorization,
WWW-Authenticate) are stripped when a redirect crosses origin
(scheme, host, or port), matching reqwest's own cross-origin redirect
behavior.

Closes #6089
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation rust Rust code changes size/L Large PR (201-500 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zeph-mcp oauth.rs: cross-origin discovered-issuer OAuth metadata has the same SSRF TOCTOU as #6057, not closable by #6069's fix

1 participant