You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/specification/draft/basic/security_best_practices.mdx
+106-5Lines changed: 106 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,7 +18,7 @@ This section gives a detailed description of attacks on MCP implementations, alo
18
18
19
19
### Confused Deputy Problem
20
20
21
-
Attackers can exploit MCP servers proxying other resource servers, creating "[confused deputy](https://en.wikipedia.org/wiki/Confused_deputy_problem)" vulnerabilities.
21
+
Attackers can exploit MCP proxy servers that connect to third-party APIs, creating "[confused deputy](https://en.wikipedia.org/wiki/Confused_deputy_problem)" vulnerabilities. This attack allows malicious clients to obtain authorization codes without proper user consent by exploiting the combination of static client IDs, dynamic client registration, and consent cookies.
22
22
23
23
#### Terminology
24
24
@@ -38,6 +38,15 @@ the third-party authorization server. This Client ID refers to the MCP server ac
38
38
to the Third-Party API. It is the same value for all MCP server to Third-Party API interactions regardless of
39
39
which MCP client initiated the request.
40
40
41
+
#### Vulnerable Conditions
42
+
43
+
This attack becomes possible when all of the following conditions are present:
44
+
45
+
- MCP proxy server uses a **static client ID** with a third-party authorization server
46
+
- MCP proxy server allows MCP clients to **dynamically register** (each getting their own client_id)
47
+
- The third-party authorization server sets a **consent cookie** after the first authorization
48
+
- MCP proxy server does not implement proper per-client consent before forwarding to third-party authorization
49
+
41
50
#### Architecture and Attack Flows
42
51
43
52
##### Normal OAuth proxy usage (preserves user consent)
@@ -99,8 +108,7 @@ sequenceDiagram
99
108
#### Attack Description
100
109
101
110
When an MCP proxy server uses a static client ID to authenticate with a third-party
102
-
authorization server that does not support dynamic client registration, the following
103
-
attack becomes possible:
111
+
authorization server, the following attack becomes possible:
104
112
105
113
1. A user authenticates normally through the MCP proxy server to access the third-party API
106
114
2. During this flow, the third-party authorization server sets a cookie on the user agent
@@ -114,8 +122,101 @@ attack becomes possible:
114
122
115
123
#### Mitigation
116
124
117
-
MCP proxy servers using static client IDs **MUST** obtain user consent for each dynamically
118
-
registered client before forwarding to third-party authorization servers (which may require additional consent).
125
+
To prevent confused deputy attacks, MCP proxy servers **MUST** implement per-client consent and proper security controls as detailed below.
126
+
127
+
##### Consent Flow Implementation
128
+
129
+
The following diagram shows how to properly implement per-client consent that runs **before** the third-party authorization flow:
130
+
131
+
```mermaid
132
+
sequenceDiagram
133
+
participant Client as MCP Client
134
+
participant Browser as User's Browser
135
+
participant MCP as MCP Server
136
+
participant ThirdParty as Third-Party AuthZ Server
137
+
138
+
Note over Client,ThirdParty: 1. Client Registration (Dynamic)
139
+
Client->>MCP: Register with redirect_uri
140
+
MCP-->>Client: client_id
141
+
142
+
Note over Client,ThirdParty: 2. Authorization Request
143
+
Client->>Browser: Open MCP server authorization URL
144
+
Browser->>MCP: GET /authorize?client_id=...&redirect_uri=...
145
+
146
+
alt Check MCP Server Consent
147
+
MCP->>MCP: Check consent for this client_id
148
+
Note over MCP: Not previously approved
149
+
end
150
+
151
+
MCP->>Browser: Show MCP server-owned consent page
152
+
Note over Browser: "Allow [Client Name] to access [Third-Party API]?"
153
+
Browser->>MCP: POST /consent (approve)
154
+
MCP->>MCP: Store consent decision for client_id
155
+
156
+
Note over Client,ThirdParty: 3. Forward to Third-Party
157
+
MCP->>Browser: Redirect to third-party /authorize
158
+
Note over MCP: Use static client_id for third-party
ThirdParty->>Browser: User authenticates & consents
162
+
ThirdParty->>Browser: Redirect with auth code
163
+
164
+
Browser->>MCP: Callback with third-party code
165
+
MCP->>ThirdParty: Exchange code for token (using static client_id)
166
+
MCP->>Browser: Redirect to client's registered redirect_uri
167
+
```
168
+
169
+
##### Required Protections
170
+
171
+
**Per-Client Consent Storage**
172
+
173
+
MCP proxy servers **MUST**:
174
+
175
+
- Maintain a registry of approved `client_id` values per user
176
+
- Check this registry **before** initiating the third-party authorization flow
177
+
- Store consent decisions securely (server-side database, or server specific cookies)
178
+
179
+
**Consent UI Requirements**
180
+
181
+
The MCP-level consent page **MUST**:
182
+
183
+
- Clearly identify the requesting MCP client by name
184
+
- Display the specific third-party API scopes being requested
185
+
- Show the registered `redirect_uri` where tokens will be sent
186
+
- Implement CSRF protection (e.g., state parameter, CSRF tokens)
187
+
- Prevent iframing via `frame-ancestors` CSP directive or `X-Frame-Options: DENY` to prevent clickjacking
188
+
189
+
**Consent Cookie Security**
190
+
191
+
If using cookies to track consent decisions, they **MUST**:
192
+
193
+
- Use `__Host-` prefix for cookie names
194
+
- Set `Secure`, `HttpOnly`, and `SameSite=Lax` attributes
195
+
- Be cryptographically signed or use server-side sessions
196
+
- Bind to the specific `client_id` (not just "user has consented")
197
+
198
+
**Redirect URI Validation**
199
+
200
+
The MCP proxy server **MUST**:
201
+
202
+
- Validate that the `redirect_uri` in authorization requests exactly matches the registered URI
203
+
- Reject requests if the `redirect_uri` has changed without re-registration
204
+
- Use exact string matching (not pattern matching or wildcards)
205
+
206
+
**OAuth State Parameter Validation**
207
+
208
+
The OAuth `state` parameter is critical to prevent authorization code interception and CSRF attacks. Proper state validation ensures that consent approval at the authorization endpoint is enforced at the callback endpoint.
- Generate a cryptographically secure random `state` value for each authorization request
213
+
- Store the `state` value server-side (in a secure session store or encrypted cookie) **only after** consent has been explicitly approved
214
+
- Set the `state` tracking cookie/session **immediately before** redirecting to the third-party identity provider (not before consent approval)
215
+
- Validate at the callback endpoint that the `state` query parameter exactly matches the stored value in the callback request's cookies or in the request's cookie-based session
216
+
- Reject any callback requests where the `state` parameter is missing or does not match
217
+
- Ensure `state` values are single-use (delete after validation) and have a short expiration time (e.g., 10 minutes)
218
+
219
+
The consent cookie or session containing the `state` value **MUST NOT** be set until **after** the user has approved the consent screen at the MCP server's authorization endpoint. Setting this cookie before consent approval renders the consent screen ineffective, as an attacker could bypass it by crafting a malicious authorization request.
0 commit comments