mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-19 03:54:18 +02:00
Fix confused deputy attack via consent binding cookie (#3201)
* Add consent binding cookie to prevent confused deputy attacks (GHSA-rww4-4w9c-7733) The OAuthProxy's consent page verified user intent but didn't bind the consenting browser to the IdP callback. An attacker could intercept the upstream authorization URL after consent and send it to a victim, whose browser would complete the flow without having the consent cookie. This adds a signed consent binding cookie set during consent approval (both manual and auto-approve paths) and verified in the IdP callback handler. A different browser won't have this cookie and gets a 403. * Use startswith for URL assertion in consent binding test * Store consent bindings as per-transaction map to support parallel flows * Only accept __Host- consent binding cookie on HTTPS * chore: Update SDK documentation --------- Co-authored-by: marvin-context-protocol[bot] <225465937+marvin-context-protocol[bot]@users.noreply.github.com>
This commit is contained in:
parent
2dcbb944a8
commit
016b9f90e0
7 changed files with 415 additions and 18 deletions
|
|
@ -22,7 +22,7 @@ Stored server-side to track active authorization flows with client context.
|
|||
Includes CSRF tokens for consent protection per MCP security best practices.
|
||||
|
||||
|
||||
### `ClientCode` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L61" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ClientCode` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L62" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Client authorization code with PKCE and upstream tokens.
|
||||
|
|
@ -31,7 +31,7 @@ Stored server-side after upstream IdP callback. Contains the upstream
|
|||
tokens bound to the client's PKCE challenge for secure token exchange.
|
||||
|
||||
|
||||
### `UpstreamTokenSet` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L79" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `UpstreamTokenSet` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L80" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Stored upstream OAuth tokens from identity provider.
|
||||
|
|
@ -41,7 +41,7 @@ and stored in plaintext within this model. Encryption is handled transparently
|
|||
at the storage layer via FernetEncryptionWrapper. Tokens are never exposed to MCP clients.
|
||||
|
||||
|
||||
### `JTIMapping` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L101" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `JTIMapping` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L102" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Maps FastMCP token JTI to upstream token ID.
|
||||
|
|
@ -50,7 +50,7 @@ This allows stateless JWT validation while still being able to look up
|
|||
the corresponding upstream token when tools need to access upstream APIs.
|
||||
|
||||
|
||||
### `RefreshTokenMetadata` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L113" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `RefreshTokenMetadata` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L114" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Metadata for a refresh token, stored keyed by token hash.
|
||||
|
|
@ -59,7 +59,7 @@ We store only metadata (not the token itself) for security - if storage
|
|||
is compromised, attackers get hashes they can't reverse into usable tokens.
|
||||
|
||||
|
||||
### `ProxyDCRClient` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L135" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ProxyDCRClient` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L136" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Client for DCR proxy with configurable redirect URI validation.
|
||||
|
|
@ -89,7 +89,7 @@ arise from accepting arbitrary redirect URIs.
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `validate_redirect_uri` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L166" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `validate_redirect_uri` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/server/auth/oauth_proxy/models.py#L167" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
validate_redirect_uri(self, redirect_uri: AnyUrl | None) -> AnyUrl
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue