Skip to content
Betav0.61.0
All articles

MCP Python SDK redirected custom headers off-origin

A medium-severity flaw in the MCP Python SDK followed cross-origin redirects and forwarded custom API keys. How it differs from the TypeScript OAuth issuer bug.

By The SpanDock team

4 min read

Diagram of a trusted MCP URL returning a redirect that carries an X-API-Key header to another origin

On 2 October 2026 the MCP Python SDK maintainers published advisory GHSA-5h93-6whr-6q8j: Streamable HTTP and SSE client transports followed HTTP redirects to any host, and custom headers such as X-API-Key went with them. On 307 or 308 redirects the request body was re-sent too. Severity is CVSS 5.9 medium (advisory label: Moderate). Say medium, not high or critical. This is a different failure mode from the TypeScript OAuth issuer confusion disclosed days earlier.

Context: what leaked and what did not

Affected mcp package versions: 1.8.0–1.29.1 and 2.0.0–2.1.1. Fixed in 1.30.0 and 2.2.0. Anyone able to make a trusted endpoint redirect elsewhere—a stale redirect to a lapsed domain, a misrouted proxy rule, or redirect logic an attacker can influence—could capture custom header material. A server that is itself malicious gains nothing this way; it already receives the client's requests directly.

A lone Authorization bearer header was not exposed: the HTTP library already drops it on cross-origin redirects. OAuth client providers in the SDK followed redirects on discovery, registration and token requests the same way as the transports.

In scope if you use the SDK as an MCP client over HTTP through streamable_http_client, streamablehttp_client, sse_client, ClientSessionGroup with HTTP parameters, or the internal create_mcp_http_client helper—including an HTTP client you passed with follow_redirects=True.

Not affected: MCP servers, stdio clients, and clients already supplied with follow_redirects left at its default of False.

Analysis: same-origin redirects after the fix

After upgrade, transports and OAuth providers follow a redirect only when it stays on the endpoint's origin (same scheme, host and port, or an http to https upgrade on the same host) and keeps the request method. Any other redirect fails with an error naming the target. Until you upgrade, supply your own HTTP client with follow_redirects=False. If a client may already have followed a redirect to a host you do not control, rotate the credentials it carried.

Contrast with GHSA-6qxp-vccf-f47h in the TypeScript SDK (write-up): that issue sent refresh tokens and client secrets to an authorization server chosen by the MCP server, rated CVSS 7.5 high. Different language, different credential class, different CVSS word. Track them as separate tickets.

Both fit the broader lesson from MCP servers and SSRF / untrusted URLs: once an agent HTTP client trusts server-controlled locations, ordinary web redirect behaviour becomes a credential boundary problem.

Redirect policy as a security control

Browser vendors spent years teaching developers that cookies and authorization material must not follow cross-site redirects casually. Agent HTTP clients rebuilt the same footgun with custom headers. Security reviews of MCP clients should ask three questions: which headers are attached by default, whether redirects are followed, and whether 307/308 behaviour re-sends bodies. Those answers belong in the architecture decision record for every new connector.

Also inventory who can change the DNS or reverse-proxy rules in front of "trusted" MCP endpoints. A temporary redirect for a maintenance page that points at a marketing domain is enough to move an X-API-Key. Certificate transparency and redirect monitoring are not exotic for teams that already watch OAuth redirect URIs.

OAuth discovery and registration paths in the same SDK followed redirects too. Patching transports without upgrading OAuth client helpers leaves half the surface open. Prefer a single mcp package pin across the organisation rather than a mix of 1.x and 2.x lines that lag independently.

What it means for engineering and security leaders

Custom API keys in headers are first-class secrets in MCP clients. Teams often put X-API-Key on MCP HTTP clients because bearer handling felt "solved." This advisory shows why that pattern needs the same redirect policy as browsers apply to cookies.

Stale infrastructure is enough. You do not need a purpose-built malicious MCP server. A forgotten redirect on a domain you once owned is enough.

Upgrade paths must include dependency bots for agent SDKs. Python mcp sits beside application frameworks in the same risk class for credential forwarding.

Testing after the upgrade

After moving to 1.30.0 or 2.2.0, add a regression test that serves a cross-origin 302 from a local fixture and asserts the client refuses to follow with custom headers. The same test should cover 307 with a body. Catching a future dependency downgrade is cheaper than another rotation exercise.

If your organisation still needs intentional same-host http to https upgrades, verify that path still works; the advisory describes that as allowed after the fix. Cross-host redirects that were part of a convenience URL shortener must be replaced with final HTTPS URLs in configuration.

Practical takeaways for this week

  • Upgrade mcp to 1.30.0+ or 2.2.0+ everywhere you run HTTP/SSE MCP clients.
  • Until then, force follow_redirects=False on client HTTP stacks.
  • Rotate any API keys that may have been sent after a cross-origin redirect.
  • Search configs for X-API-Key and similar custom headers on MCP clients; prefer patterns that do not rely on redirect-safe forwarding.
  • File separate remediation items for this advisory and the TypeScript OAuth issuer issue.
  • Point endpoint URLs at final hosts if you previously depended on cross-host redirects (those stop working after the fix).

Where SpanDock fits

With the MCP gateway (Premium and Enterprise, and the trial), AI tools on each computer call SpanDock's MCP server locally; the server keeps connector credentials in its credential store and never shows them again, never logs them, and never sends them to computers. That design reduces how often client machines carry long-lived API keys to arbitrary MCP URLs. It does not replace upgrading the Python SDK in any custom HTTP MCP client you still run.

Sources

  1. HTTP client transports followed cross-origin redirects carrying custom headers and bodies (GHSA-5h93-6whr-6q8j)
  2. OAuth client could send credentials to an authorization server chosen by the MCP server (TypeScript GHSA-6qxp-vccf-f47h)
Cookie categories

Details: Cookie Policy.