Skip to content

Ignore proxy forwarding headers by default for OAuth resource metadata#2550

Open
SamMorrowDrums wants to merge 1 commit into
mainfrom
sammorrowdrums/trust-proxy-headers-opt-in
Open

Ignore proxy forwarding headers by default for OAuth resource metadata#2550
SamMorrowDrums wants to merge 1 commit into
mainfrom
sammorrowdrums/trust-proxy-headers-opt-in

Conversation

@SamMorrowDrums
Copy link
Copy Markdown
Collaborator

@SamMorrowDrums SamMorrowDrums commented May 26, 2026

What

By default, ignore X-Forwarded-Host and X-Forwarded-Proto when constructing the URLs that appear in the WWW-Authenticate: Bearer resource_metadata=... response header and the /.well-known/oauth-protected-resource body. Add an opt-in --trust-proxy-headers flag (and GITHUB_TRUST_PROXY_HEADERS env) for deployments that sit behind a trusted internal forwarder. --base-url continues to take precedence in all cases.

Why

GetEffectiveHostAndScheme previously read X-Forwarded-Host / X-Forwarded-Proto unconditionally. In an HTTP-mode self-host that does not set --base-url and is not fronted by a proxy that strips those headers, a client that can inject them can influence the URL we advertise to MCP clients for OAuth discovery.

This is a hardening change rather than a true vulnerability — exploitation requires HTTP mode without --base-url plus an attacker already positioned to set request headers, which is usually a sign of a bigger problem — but the unsafe default is worth closing.

Behavior

  • Default: effective host comes from r.Host (then localhost); effective scheme comes from TLS state (then http).
  • --base-url set: unchanged, always wins.
  • --trust-proxy-headers (or GITHUB_TRUST_PROXY_HEADERS=1): restores the previous header-honoring behavior for trusted internal forwarders that need to preserve the originating hostname per request.

X-Forwarded-Host and X-Forwarded-Proto were unconditionally honored when
constructing OAuth resource metadata URLs. In HTTP-mode deployments that
do not set --base-url and are not fronted by a proxy that strips these
headers, this lets an on-path client influence the URL advertised in
WWW-Authenticate and the /.well-known/oauth-protected-resource body.

This is a hardening change rather than a true vulnerability — exploiting
it requires HTTP without --base-url plus an attacker already positioned
to inject the header — but the unsafe default is worth closing.

Default behavior now derives host/scheme from r.Host and the TLS state.
Setups that rely on a trusted internal forwarder (e.g. an in-cluster
gateway that needs to preserve the originating hostname per request) can
opt back in with --trust-proxy-headers / GITHUB_TRUST_PROXY_HEADERS=1.
--base-url continues to take precedence in all cases.

Co-authored-by: Copilot <[email protected]>
@SamMorrowDrums SamMorrowDrums requested a review from a team as a code owner May 26, 2026 12:08
Copilot AI review requested due to automatic review settings May 26, 2026 12:08
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Hardens OAuth protected-resource metadata URL construction by ignoring X-Forwarded-Host / X-Forwarded-Proto by default, with an explicit opt-in for trusted proxy deployments.

Changes:

  • Add TrustProxyHeaders config plumbing from CLI/server config into OAuth URL derivation.
  • Gate forwarded-header usage in GetEffectiveHostAndScheme behind TrustProxyHeaders.
  • Update tests + docs to reflect the new default and opt-in behavior.
Show a summary per file
File Description
pkg/http/server.go Plumbs TrustProxyHeaders through ServerConfig into OAuth config.
pkg/http/oauth/oauth.go Gates forwarded-header reads on TrustProxyHeaders.
pkg/http/oauth/oauth_test.go Adds/updates test cases for default-ignore vs opt-in forwarded headers.
cmd/github-mcp-server/main.go Adds --trust-proxy-headers flag and viper binding.
docs/streamable-http.md Documents default behavior and trusted-proxy opt-in.

Copilot's findings

  • Files reviewed: 5/5 changed files
  • Comments generated: 1

Comment thread pkg/http/oauth/oauth.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants