Skip to content

fix: prevent MCP transport auth header from leaking to downstream OpenAPI APIs (#3260)#3262

Merged
jlowin merged 3 commits intoPrefectHQ:mainfrom
stakeswky:fix/3260-openapi-auth-header-leak
Feb 21, 2026
Merged

fix: prevent MCP transport auth header from leaking to downstream OpenAPI APIs (#3260)#3262
jlowin merged 3 commits intoPrefectHQ:mainfrom
stakeswky:fix/3260-openapi-auth-header-leak

Conversation

@stakeswky
Copy link
Copy Markdown
Contributor

Problem

When an MCP server is created with FastMCP.from_openapi() and served over Streamable HTTP, the get_http_headers() call in OpenAPITool.run() forwards the incoming MCP transport's Authorization header to the downstream API, overwriting the API key configured on the httpx client.

This means the downstream API receives the MCP client's auth token instead of the intended API key, causing auth failures (503/401/403).

This is a security issue — MCP transport credentials should never leak to downstream third-party APIs.

Root Cause

Two problems in OpenAPITool.run() (components.py):

  1. get_http_headers() does not exclude authorization from forwarded headers
  2. request.headers.update(mcp_headers) overwrites existing headers, while the client headers block above uses if key not in request.headers (non-overwriting) — inconsistent behavior
# Client headers: non-overwriting ✓
if self._client.headers:
    for key, value in self._client.headers.items():
        if key not in request.headers:
            request.headers[key] = value

# MCP headers: overwrites everything ✗
mcp_headers = get_http_headers()
if mcp_headers:
    request.headers.update(mcp_headers)  # <-- overwrites Authorization!

Fix

  1. Add authorization to exclude_headers in get_http_headers() (dependencies.py) — MCP transport credentials should not be forwarded to downstream APIs by default
  2. Change MCP header forwarding to use the same non-overwriting pattern as client headers — only set if key not already present
# After fix: consistent non-overwriting behavior
mcp_headers = get_http_headers()
if mcp_headers:
    for key, value in mcp_headers.items():
        if key not in request.headers:
            request.headers[key] = value

Impact

  • Security: Prevents MCP client credentials from leaking to third-party APIs
  • Correctness: httpx client's configured API key is now respected
  • Consistency: Both client headers and MCP headers use the same non-overwriting pattern

Fixes #3260

…nAPI APIs (PrefectHQ#3260)

Two issues in OpenAPITool.run():

1. get_http_headers() does not exclude 'authorization', so the MCP
   client's auth token is included in forwarded headers.

2. mcp_headers.update() overwrites existing request headers, including
   the Authorization header that was already set from the httpx client's
   configured API key.

Fix:
- Add 'authorization' to exclude_headers in get_http_headers() to
  prevent MCP transport credentials from being forwarded by default.
- Change mcp_headers forwarding to use the same non-overwriting pattern
  as client headers (only set if key not already present), making the
  behavior consistent and preventing accidental overwrites.

Fixes PrefectHQ#3260
@marvin-context-protocol marvin-context-protocol Bot added bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. openapi Related to OpenAPI integration, parsing, or code generation features. auth Related to authentication (Bearer, JWT, OAuth, WorkOS) for client or server. http Related to HTTP transport, networking, or web server functionality. high-priority labels Feb 21, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4bcfb389c4

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

"expect",
"accept",
# Auth headers should not be forwarded to downstream APIs
"authorization",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid stripping Authorization in shared header helper

Adding authorization to the default exclude_headers in get_http_headers() changes behavior for every caller of this utility, not just OpenAPI tools. Both proxy client transports (src/fastmcp/client/transports/http.py:98 and src/fastmcp/client/transports/sse.py:72) rely on get_http_headers() | self.headers to forward incoming MCP request headers upstream, so a FastMCP proxy in front of an authenticated upstream MCP server will now drop the caller’s bearer token and fail authorization. This is a regression for authenticated proxy deployments; the authorization exclusion should be limited to the OpenAPI forwarding path instead of the shared helper default.

Useful? React with 👍 / 👎.

The authorization exclusion is correct for the default case (OpenAPI
tools should not forward MCP transport credentials), but proxy
transports need auth headers forwarded to upstream MCP servers.

The new `include` parameter lets callers opt specific headers back in
despite the default exclusion set. Proxy transports now explicitly
request authorization forwarding.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 69d483bc21

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"keep-alive",
"expect",
"accept",
"authorization",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve Authorization in default header helper

Adding "authorization" to the default exclusion list makes get_http_headers() drop auth headers for every caller, not just the OpenAPI forwarding path. CurrentHeaders delegates directly to get_http_headers() (src/fastmcp/server/dependencies.py:1051), so tools/middleware that read headers.get("authorization") now silently lose bearer tokens and can fail custom auth logic in HTTP transports. This behavior change should be scoped to the OpenAPI forwarding use case or CurrentHeaders should explicitly opt back in with include={"authorization"}.

Useful? React with 👍 / 👎.

CurrentHeaders is user-facing — tools use it to inspect the caller's
auth token for custom logic. Reading a header in your own code is safe;
the exclusion is meant to prevent blindly forwarding it to third-party
APIs.
@jlowin
Copy link
Copy Markdown
Member

jlowin commented Feb 21, 2026

@stakeswky thank you! making some tweaks to avoid breaking proxy forwarding

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

Labels

auth Related to authentication (Bearer, JWT, OAuth, WorkOS) for client or server. bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. high-priority http Related to HTTP transport, networking, or web server functionality. openapi Related to OpenAPI integration, parsing, or code generation features.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI tool forwards MCP transport auth headers to downstream APIs

2 participants