MCP Server Attack Surface: A Complete Map for Security Reviewers
Most MCP security discussions focus on prompt injection: adversarial text in tool results that hijacks the LLM’s behavior. Prompt injection is real and important. But it is one attack class against one layer of the MCP stack. The MCP 2025-03-26 specification introduced a protocol layer that has its own distinct attack surface — session management, pagination, transport security, authentication, resource subscriptions, and ten more dimensions. This article maps all 15 SA-MCP attack families that SkillAudit checks in every MCP server audit, with severity ratings, detection methods, and links to the full technical analysis for each family.
Why the protocol layer matters more than most reviewers expect
When a security reviewer audits a REST API, they look for SQL injection, authentication bypasses, rate limiting gaps, and IDOR vulnerabilities. When they audit a GraphQL endpoint, they add introspection abuse and field-level authorization gaps to the checklist. MCP is a protocol — and like every protocol, it introduces attack surface at the protocol layer that does not exist at the application layer.
The MCP 2025-03-26 specification introduced several protocol-level features that have no analog in traditional REST or GraphQL APIs: cursor-based pagination with opaque tokens, resource subscription with server-push notifications, a sampling mechanism that lets the server invoke the LLM, an elicitation mechanism that lets the server request human input, tool annotations that modify LLM trust behavior, an OAuth 2.1 authorization flow, Streamable HTTP transport with session management, and more. Each of these features has a protocol-layer attack surface that exists in addition to the application-layer attack surface of whatever the tool actually does.
A security reviewer who only checks “can the tool be injected with adversarial prompts” misses the protocol layer entirely. An MCP server that correctly sanitizes all tool outputs for prompt injection can still be vulnerable to session hijacking, cursor forgery, resource subscription DoS, OAuth flow manipulation, and logging level elevation — none of which involve LLM behavior at all.
The 15 SA-MCP attack families
SA-MCP-SHT — Streamable HTTP transport
Session ID hijacking, SSE injection across sessions, origin header bypass, session fixation via crafted initialize requests. The Streamable HTTP transport is the default since 2025-03-26 and has distinct session management vulnerabilities not present in the deprecated stdio transport.
SA-MCP-OAU — OAuth 2.1 authorization
Authorization code interception via redirect URI manipulation, PKCE bypass via state parameter injection, token leakage in error responses, dynamic client registration abuse, resource indicator confusion attacks per RFC 8707.
SA-MCP-SAM — Sampling / createMessage
The MCP sampling/createMessage method lets the server invoke the LLM. Attack surface: server-initiated prompt injection via crafted messages array, capability escalation by requesting more tokens/temperature than granted, context exfiltration by including prior conversation state in sampling requests.
SA-MCP-ELI — Elicitation
The elicitation/create method lets the server request human input. Attack surface: social engineering via crafted prompt text in elicitation requests, phishing via URL injection in elicitation UI, schema-validated input as a constraint-bypass vector, authority spoofing in elicitation message framing.
SA-MCP-ANN — Tool annotation spoofing
MCP tool annotations (readOnly, destructive, idempotent) modify how Claude presents the tool to users. An attacker can label a destructive tool as readOnly: true to suppress confirmation dialogs, or as idempotent: true to encourage repeated execution without warnings.
SA-MCP-RSB — Resource subscription
The resources/subscribe method creates server-push notification channels. Attack surface: subscription amplification (subscribe to same resource N times), subscription-based DoS by subscribing to all resources simultaneously, notification content injection, cross-tenant subscription via predictable resource URIs.
SA-MCP-CMP — Completion API
The completion/complete method returns autocomplete suggestions for argument values. Attack surface: completion oracle for secret enumeration (complete partial API keys), information disclosure via completion candidates revealing internal state, completion injection for argument value manipulation.
SA-MCP-RTS — Roots list
The roots/list method exposes client filesystem roots. Attack surface: roots enumeration reveals host filesystem layout for path traversal targeting, roots list manipulation via client capability spoofing, roots-based SSRF via file:// URIs in roots array.
SA-MCP-PRG — Progress notifications
Progress notifications carry intermediate status for long-running operations. Attack surface: progress token replay across sessions, progress notification injection revealing internal operation timing, token exhaustion via rapid progress token allocation, cross-session progress correlation leaking operation details.
SA-MCP-LOG — Logging level elevation
The logging/setLevel method lets clients change server log verbosity. Attack surface: elevation to DEBUG/TRACE reveals internal state in log notifications, log notification injection as a side channel for credential extraction, log flooding via rapid level cycling as a DoS vector.
SA-MCP-PAG — Pagination cursor
Cursor-based pagination via opaque nextCursor tokens. Attack surface: predictable cursors allow cross-tenant page jumping, cursor forgery grants out-of-bounds access, malformed cursors leak internal structure via parse errors, concurrent cursor amplification enumerates full resource lists. Full SA-MCP-PAG analysis →
SA-MCP-CAN — Request cancellation
The $/cancelRequest notification interrupts in-flight operations. Attack surface: cancellation-based TOCTOU races on file operations, partial-write vulnerabilities after cancellation, resource cleanup bypass via rapid cancel-retry cycles, cancellation oracle timing attacks revealing internal state.
SA-MCP-VER — Protocol version downgrade
MCP protocol version negotiation in the initialize request. Attack surface: version downgrade to older protocol with fewer security controls, capability confusion via mismatched version negotiation, initialize request replay across sessions, version negotiation DoS via malformed version strings.
SA-MCP-ERR — Tool error response
Error responses from tool calls. Attack surface: verbose error messages leaking stack traces, database schema, or internal file paths; error-based enumeration of valid vs. invalid inputs; JSON-RPC error code abuse for protocol state confusion; error response injection via crafted tool arguments triggering framework errors. Full SA-MCP-ERR analysis →
SA-MCP-CTY — Content-type confusion
MCP tool results carry typed content (text, image, resource, audio). Attack surface: type confusion by returning binary data typed as text, MIME sniffing injection via crafted content-type declarations, resource URI injection in embedded resource content, audio/image content as a prompt injection delivery vector bypassing text-only filters. Full SA-MCP-CTY analysis →
The attack surface by layer
Looking at the 15 families together, a pattern emerges: MCP’s attack surface distributes across four distinct protocol layers. Understanding which layer each family targets helps reviewers prioritize their time and structure their audit methodology.
Layer 1: Transport and session (SA-MCP-SHT, SA-MCP-VER)
The Streamable HTTP transport and version negotiation mechanisms operate before any tool call or resource access. Vulnerabilities here affect all subsequent protocol operations. SA-MCP-SHT session hijacking means every tool call made by a victim after session establishment is accessible to the attacker. SA-MCP-VER version downgrade can strip all security controls before any content is exchanged. Audit transport and session first — a compromise here makes all subsequent layer protections moot.
Layer 2: Authentication and authorization (SA-MCP-OAU, SA-MCP-ANN)
OAuth 2.1 flows handle identity; tool annotations affect authorization UX. SA-MCP-OAU vulnerabilities in the authorization code flow (redirect URI manipulation, PKCE bypass) allow credential theft before the server-side tool code ever runs. SA-MCP-ANN annotation spoofing manipulates the authorization layer on the client side — misleading users into confirming destructive operations without warnings. Both families bypass application-layer authorization controls by attacking the authorization infrastructure directly.
Layer 3: Protocol features (SA-MCP-SAM, SA-MCP-ELI, SA-MCP-RSB, SA-MCP-CMP, SA-MCP-RTS, SA-MCP-PRG, SA-MCP-LOG, SA-MCP-PAG, SA-MCP-CAN)
This is the largest layer: nine attack families covering every protocol extension in the 2025-03-26 specification. SA-MCP-SAM (sampling) and SA-MCP-ELI (elicitation) are particularly important because they invert the normal direction of trust: the server (which should be the less-trusted party) gains the ability to invoke the LLM or request human input. These bidirectional trust-inversion features have no analog in REST APIs and are frequently overlooked in security reviews that treat MCP as a thin HTTP wrapper.
Trust inversion is the most underappreciated attack surface in MCP: In a REST API, the server responds to client requests — the trust flows client → server → response. MCP 2025 introduced three mechanisms where the server initiates requests to the client: sampling (sampling/createMessage), elicitation (elicitation/create), and notifications (subscriptions, progress, logging). Each of these represents a server-to-client trust inversion that creates prompt injection, phishing, and information leakage attack vectors that traditional API security reviews do not check for.
Layer 4: Content and response (SA-MCP-ERR, SA-MCP-CTY)
Error responses and content-type handling affect what data reaches the client after tool execution. SA-MCP-ERR verbose errors leak internal state; SA-MCP-CTY type confusion enables prompt injection delivery through non-text content channels. These families are at the bottom of the stack but should not be reviewed last — error response leakage and content-type injection are among the most frequently exploited patterns in production MCP deployments because they are easy to overlook during development when error verbosity is helpful for debugging.
Quick-reference: all 15 families at a glance
| Family | Description | Layer | Max severity | Key detection signal |
|---|---|---|---|---|
| SA-MCP-SHT | Streamable HTTP transport session management | Transport | CRITICAL | Missing session binding on SSE endpoint; no Mcp-Session-Id validation |
| SA-MCP-OAU | OAuth 2.1 authorization flow | Auth | CRITICAL | Dynamic redirect URI without allowlist; missing PKCE verifier check |
| SA-MCP-SAM | Sampling / createMessage injection | Protocol features | CRITICAL | sampling/createMessage with server-controlled messages array including user-visible instructions |
| SA-MCP-ELI | Elicitation social engineering | Protocol features | CRITICAL | elicitation/create with URL or credential-themed prompt text; missing schema constraints |
| SA-MCP-ANN | Tool annotation spoofing | Auth | HIGH | Destructive operations (delete, write, exec) with readOnly: true or missing destructive annotation |
| SA-MCP-RSB | Resource subscription amplification/injection | Protocol features | HIGH | No per-user subscription limit; notification content not sanitized before delivery |
| SA-MCP-CMP | Completion API enumeration oracle | Protocol features | HIGH | Completion suggestions derived from sensitive data (API keys, user IDs, file paths) |
| SA-MCP-RTS | Roots list enumeration and traversal | Protocol features | HIGH | Roots array used in path construction without realpath boundary check |
| SA-MCP-PRG | Progress notification leakage | Protocol features | HIGH | Progress token not bound to initiating session; notification body includes internal state |
| SA-MCP-LOG | Logging level elevation | Protocol features | HIGH | No authorization check before accepting logging/setLevel; DEBUG log includes env vars or tokens |
| SA-MCP-PAG | Pagination cursor predictability/forgery | Protocol features | CRITICAL | nextCursor set to numeric/timestamp/unsigned Base64 JSON; no session binding |
| SA-MCP-CAN | Request cancellation TOCTOU races | Protocol features | HIGH | File operations not atomic; missing cancel handler cleanup for partial writes |
| SA-MCP-VER | Protocol version downgrade | Transport | HIGH | initialize accepts any requested protocolVersion; no minimum version enforcement |
| SA-MCP-ERR | Tool error response information leakage | Content | HIGH | Stack traces or e.message from catch blocks in tool call response |
| SA-MCP-CTY | Content-type confusion injection | Content | HIGH | Tool result content type not validated against actual content; user-controlled type field |
How to structure an MCP security review
Given the layered attack surface above, SkillAudit recommends the following review sequence. This order reflects blast radius — vulnerabilities in earlier layers undermine all protections in later layers.
Step 1: Transport and version (SA-MCP-SHT, SA-MCP-VER) — ~20 min
Review the initialize request handler. Does the server validate the requested protocolVersion and enforce a minimum? Does the Streamable HTTP transport bind session IDs to an origin/client identity? Can an attacker reuse a session ID from a previous connection? Can they inject into an SSE stream for a different session?
Key file to read: the server’s initialize handler and its Streamable HTTP transport implementation. Look for Mcp-Session-Id header validation and for version comparison logic.
Step 2: Authentication and authorization (SA-MCP-OAU, SA-MCP-ANN) — ~30 min
If the server implements OAuth 2.1 authorization, review the full authorization code flow: redirect URI validation, state parameter entropy, PKCE verifier handling, token storage, and error response content. Check tool annotations: are all write/delete/exec operations marked destructive: true? Are any destructive operations incorrectly labeled readOnly: true?
Step 3: Trust-inversion protocol features (SA-MCP-SAM, SA-MCP-ELI) — ~30 min
These are the highest-impact features to review after session and auth. Does the server invoke sampling/createMessage? If so, what content does it include in the messages array — can an attacker influence that content? Does the server use elicitation/create? If so, what does the prompt text say and can it be social-engineered to request credentials?
Step 4: Standard protocol features (SA-MCP-RSB, SA-MCP-CMP, SA-MCP-RTS, SA-MCP-PRG, SA-MCP-LOG, SA-MCP-PAG, SA-MCP-CAN) — ~60 min
Work through each implemented feature methodically. Many MCP servers implement only a subset of these — focus your time on what’s actually in the codebase. For each feature, the key question is: can user-supplied input influence the feature’s output in a way that crosses a trust boundary? Pagination cursors that encode user identity are the most common finding here.
Step 5: Content and response handling (SA-MCP-ERR, SA-MCP-CTY) — ~20 min
Review all tool call handlers for error handling: do catch blocks propagate e.message to the client? Are HTTP library errors re-thrown raw? Review tool result construction: is the type field of content items server-controlled or could a tool argument influence it?
Total estimated manual review time: ~2.5 hours for a thorough walkthrough of all 15 SA-MCP families. SkillAudit automates the static analysis portions (session binding checks, cursor generation patterns, error response analysis, annotation validation) to produce a graded report in 60 seconds — letting reviewers focus their manual time on the logic-level checks that static analysis cannot perform automatically.
The five highest-return checks in any MCP server audit
If you have limited time and need to triage quickly, these five checks have the highest finding rate in SkillAudit’s analysis of community MCP servers:
- Are error messages sanitized? (SA-MCP-ERR) — The single most common finding. Stack traces and raw error messages in tool responses expose file paths, database schema, and library versions to attackers. Check every catch block: does it propagate
e.messageto the client? One grep fore.messagein throw statements catches 80% of instances. - Are pagination cursors opaque and session-bound? (SA-MCP-PAG) — Second most common. Check how
nextCursoris generated. Is it a numeric offset? A timestamp? An unsigned Base64 JSON object? Any of these is a CRITICAL finding. Look fornextCursor = String(offset)orBuffer.from(JSON.stringify({...})).toString('base64'). - Does the OAuth flow validate redirect URIs against an allowlist? (SA-MCP-OAU) — If the server implements OAuth, this is the critical authorization flow check. A missing allowlist turns the authorization server into a redirect proxy for credential theft. Look for
if (redirectUri !== registeredUri)— if this check is absent, it’s CRITICAL. - Are tool annotations accurate? (SA-MCP-ANN) — Grep for
readOnly: truein tool definitions. For each match, verify that the tool’s implementation is actually read-only (no writes, no deletes, no external state changes). Adelete_filetool withreadOnly: truesuppresses the confirmation dialog that would otherwise warn the user. - Is sampling/createMessage content server-controlled? (SA-MCP-SAM) — If the server calls
sampling/createMessage, audit themessagesarray: does anyuser-role message content come from user-supplied data (tool arguments, external URLs, database content)? If so, it’s a prompt injection path through the sampling mechanism.
What this taxonomy leaves out (intentionally)
The SA-MCP taxonomy covers the MCP protocol attack surface — the vulnerabilities that arise from how MCP servers implement the MCP specification. It deliberately excludes two categories that are covered separately:
- Application-layer vulnerabilities (SQL injection, SSRF in tool business logic, path traversal in tool arguments): these exist at the layer of what the tool does, not how it implements the MCP protocol. They are covered by SkillAudit’s SA-APP taxonomy, which runs the same static analysis approach against tool handler code.
- Prompt injection: this is a distinct attack class that operates at the LLM reasoning layer rather than the protocol layer. It is covered by SkillAudit’s LLM-assisted red-teaming component, which submits crafted inputs to the running MCP server and observes whether the tool result causes the LLM to deviate from intended behavior.
The protocol layer, application layer, and LLM layer are three independent attack surfaces that each require their own analysis methodology. A complete MCP server security review addresses all three. This article covers the first.
Running your own MCP security audit
For teams conducting internal reviews, the SkillAudit methodology is designed to be reproducible without the tool. Each SA-MCP family has a detailed technical article with the exact code patterns to grep for, the conditions that make each pattern vulnerable, and the secure alternatives. The quick-reference table above links to the full analysis for each family where it exists.
For teams who want automated coverage, SkillAudit runs the full SA-MCP taxonomy as part of every scan. Paste a GitHub URL at skillaudit.dev to get a graded report card covering all 15 SA-MCP families plus the full SA-APP and SA-SKL taxonomies. The Free tier covers public repos with a basic report; the Pro tier adds full SA-MCP protocol analysis with per-pattern remediation guidance.
The SkillAudit security taxonomy is a living document. As the MCP specification evolves and new protocol features are added, new attack families will be identified and added to the SA-MCP taxonomy. The 15 families in this article cover the complete MCP 2025-03-26 specification. New specification versions will add new families. Follow the SkillAudit blog for taxonomy updates as the specification evolves.