Topic: mcp server security owasp
MCP server security and OWASP — mapping the API Top 10 and LLM Top 10 onto Model Context Protocol
OWASP's two most-cited threat lists for our era — the API Security Top 10 (2023) and the Top 10 for LLM Applications (2025) — both have something to say about MCP servers, and neither is a perfect fit. This is an honest mapping of each category onto the MCP threat surface, with corpus examples from 101 of the most-installed Claude skills and MCP servers and notes on what doesn't translate.
TL;DR
Six of the OWASP API Top 10 categories map cleanly onto MCP server threats — most notably SSRF (API7), Broken Authentication (API2), Security Misconfiguration (API8), and Improper Inventory Management (API9). Three of the OWASP LLM Top 10 — Insecure Plugin Design (LLM07), Excessive Agency (LLM08), and Sensitive Information Disclosure (LLM06) — are essentially describing MCP servers under another name. Three categories from the API list (BOLA, BFLA, Unrestricted Business Flows) translate poorly because MCP doesn't have business-object semantics. The MCP-specific surface that neither list captures cleanly is credential echo into tool response (38% of our corpus), prompt-injection of tool I/O, and permission scope vs. handler implementation drift. Below: each category with definition, MCP-shape, corpus example, prevention, and a coverage signal for SkillAudit's six-axis review.
Why the mapping isn't 1:1
Three observations explain why neither OWASP list maps perfectly onto MCP:
- The API Top 10 was authored against HTTP API surfaces. Its threat model assumes object-shaped resources, ID-based addressing, REST verbs, and an authenticated user identity flowing through requests. MCP doesn't have those — its surface is "tool calls from an LLM acting on user instructions," and most of the tool calls don't have an object-ID concept at all. So categories like Broken Object Level Authorization (API1) translate weakly.
- The LLM Top 10 was authored against LLM-application surfaces broadly. Its language anticipates RAG, agentic actions, and plugins. The category that is most-clearly MCP — Insecure Plugin Design (LLM07) — is at MCP's center, but the list also includes categories (Model DoS, Training Data Poisoning, Model Theft) that are about the LLM itself, not the plugin/tool layer.
- The MCP-specific surface is shaped by the protocol, not the language. What "untrusted input" means in MCP — tool-call arguments, prompt templates, environment-variable reads in handler code — has no single home in either list. The combination of "tool-call argument" + "automated invocation by an LLM" + "first-party server code" is what makes the threat shape distinct.
The right way to use OWASP for MCP is as a vocabulary rather than a checklist. The categories give you names to put on findings. The mapping below shows where each name applies cleanly, where it stretches, and where you need MCP-specific language instead.
OWASP API Security Top 10 (2023) → MCP
API1: Broken Object Level Authorization (BOLA)
API definition: server fails to verify the requesting user is authorized for the specific object ID being accessed.
MCP shape: stretches. Most MCP servers don't expose a per-object-ID surface — they expose tool handlers parameterized by free-text arguments. The closest pattern is a tool like read_file({path}) that doesn't validate the path is inside an allow-listed directory. That isn't strictly BOLA in the API sense, but the same threat shape — caller bypassing intended scope by varying the input — applies.
Corpus signal: ~5% of our corpus has a path-traversal-shaped finding in a file-read tool handler. Caught under our security axis.
Prevention: deny-by-default scope. resolve() the path, compare against the allow-list root, reject if it escapes.
API2: Broken Authentication
API definition: attacker can compromise auth tokens, session, or identity.
MCP shape: direct fit, common pattern. MCP servers frequently authenticate to upstream services (GitHub, Cloudflare, Supabase, etc.) using a user-provided token in process.env. Broken-auth findings in this surface are: token logged to stdout/stderr, token echoed in tool responses, token used over plaintext HTTP, token sent on redirect. The redirect case is the deepest one — fetch(${baseUrl}/path) with a static Authorization: Bearer ${env.X} header that follows a 302 to an attacker-controlled host leaks the token. Detail: anatomy of a credential leak.
Corpus signal: 38% credential-handling findings.
Prevention: never read secrets into response paths. Strip Authorization on cross-host redirect (or pin redirect: 'manual'). Document which env vars are secret and don't log them. Static rules catch the easy patterns; LLM-assist catches the dynamic-base case.
API3: Broken Object Property Level Authorization
API definition: over-broad property exposure (mass-assignment-style failures).
MCP shape: stretches. The MCP equivalent is a tool handler that returns more data than the caller asked for — e.g., a get_user({id}) handler that returns the full user record including password_hash. Less common than the API surface because MCP responses are typically free-text, not structured objects, but the pattern shows up in DB-shaped servers.
Corpus signal: ~3%, mostly in DB-wrapper servers.
Prevention: explicit response-shape allowlists. Don't SELECT *; project to a defined column set.
API4: Unrestricted Resource Consumption
API definition: attacker exhausts CPU, memory, bandwidth, or wallet by submitting expensive requests.
MCP shape: direct fit, often overlooked. An MCP server that runs git log with no max-line cap, or fetches a remote URL with no size cap, or invokes an upstream LLM with no token cap, is rate-limited only by the client's politeness. We've seen this turn into wallet-burning behavior on tools that paginate upstream APIs without bounding the page count.
Corpus signal: ~12% of our corpus has at least one unbounded-consumption pattern. Caught under the security axis with a separate sub-finding class.
Prevention: bound every external call (size, timeout, page count). Add an in-process budget. Document the bound so callers can plan.
API5: Broken Function Level Authorization (BFLA)
API definition: attacker invokes admin-only functions because authorization isn't checked at the function level.
MCP shape: doesn't translate. MCP servers don't have an admin-vs-user privilege concept; they run with whatever privileges the host process has. The closest pattern is the permissions-hygiene axis — declared tools that exceed actual usage — but that's a different threat shape.
Corpus signal: n/a; permissions hygiene is its own axis.
Prevention: declare narrowly; if a tool isn't used, don't register it.
API6: Unrestricted Access to Sensitive Business Flows
API definition: automated abuse of legitimate functionality (scraping, signup spam, scalping).
MCP shape: doesn't translate at the protocol layer. The threat exists at the upstream service the MCP server proxies to, not at the MCP server itself. A SkillAudit review will not flag this because the surface isn't ours; it's the upstream's.
Corpus signal: n/a.
Prevention: defense-in-depth in the upstream service.
API7: Server Side Request Forgery (SSRF)
API definition: server fetches a URL controlled by the attacker, reaching internal-network or sensitive-host destinations.
MCP shape: direct fit, the most common high-severity finding in the corpus. Tool handlers like fetch_url({url}) with no allow-list, no IP-block check, and no protocol restriction are textbook SSRF. The dynamic-base variant — fetch(`${baseUrl}/${path}`) where baseUrl comes from an environment variable or a tool argument — is what most default SAST rules miss. The server runs inside the user's network, often inside an agent that has cloud credentials in env, so SSRF is a credentials-stealing primitive too.
Corpus signal: 50% — by far the dominant finding class.
Prevention: URL allow-list, parsed-host comparison (not string prefix), deny RFC 1918 + 127/8 + 169.254.169.254 + IPv6 link-local, deny file:// and gopher:// schemes, manual redirect handling. Detail in best practices.
API8: Security Misconfiguration
API definition: insecure defaults, exposed debug endpoints, missing hardening.
MCP shape: direct fit. MCP servers commonly ship with debug logging on by default, with verbose error messages that echo arguments back, with a missing or permissive CORS config when an HTTP transport is used, with no origin check on SSE endpoints. We've also seen servers that listen on 0.0.0.0 when they should listen on 127.0.0.1.
Corpus signal: ~18%; caught across security and credential axes.
Prevention: production-default flag set. Strip arg values from error messages. Pin transport to localhost when running over HTTP.
API9: Improper Inventory Management
API definition: deprecated/v1/staging endpoints kept exposed; no clear inventory of versions.
MCP shape: direct fit, manifests as protocol-version drift and unmaintained branches. A server that supports MCP protocol 0.6 with a v1 branch still active and unpatched is the typical shape. Archived repositories are the strongest signal here.
Corpus signal: 9 of 101 corpus servers were archived; covered under the maintenance axis. Detail.
Prevention: tag releases, advisory-feed registration, deprecation notices on old protocol versions, archived-repo signal in package.json.
API10: Unsafe Consumption of APIs
API definition: the API trusts upstream APIs more than it should — accepting their responses without validation.
MCP shape: direct fit, frequently underweighted. MCP servers fetch from upstream services and pass the responses to the LLM. If the upstream is compromised or malicious, its response becomes a prompt-injection vector against the agent calling the MCP server. A web-search MCP that returns raw HTML is a textbook example.
Corpus signal: ~22%, partially covered by our prompt-injection axis (LLM-assisted probe).
Prevention: response-shape validation, sanitization of user-visible upstream content, awareness that "the upstream is trusted" is rarely true at LLM scale. Detail: testing the prompt-injection axis.
OWASP Top 10 for LLM Applications (2025) → MCP
LLM01: Prompt Injection
LLM definition: user-controlled or upstream-controlled text is interpreted as instructions by the LLM.
MCP shape: direct fit, two distinct surfaces. Direct injection: a tool handler that accepts a free-text argument and feeds it back to the LLM unchanged. Indirect injection: a tool handler that fetches data from an upstream (web, GitHub, S3) and returns the upstream's content to the LLM verbatim. The indirect case is harder and more common; an attacker who can post to a public forum can sometimes drive an agent's behavior via a search MCP that scrapes that forum.
Corpus signal: we LLM-probe every server in the corpus; ~30% have at least one prompt-injection finding under our methodology.
Prevention: structured-output formatting (return JSON, not free text, where possible), source-attribution tagging in tool responses, defense-in-depth at the agent's system prompt. Detail: engine v0.3 calibration delta.
LLM02: Insecure Output Handling
LLM definition: downstream consumer trusts LLM output without validation.
MCP shape: partial fit, more about the agent than the MCP server. The MCP-side responsibility is to clearly mark untrusted-source content; the agent-side responsibility is to not execute it as code. We touch this under the documentation-completeness axis (servers should document which response fields contain untrusted content).
Corpus signal: ~5% of our corpus has any explicit untrusted-content marking.
Prevention: tag response sections with source: "external" or equivalent. Document trust boundaries.
LLM03: Training Data Poisoning
LLM definition: attacker poisons the training corpus.
MCP shape: doesn't translate. MCP servers don't influence training. We don't review for this.
LLM04: Model Denial of Service
LLM definition: attacker exhausts model context window or token budget.
MCP shape: partial fit. Overlaps with API4 (Unrestricted Resource Consumption). An MCP server that returns 200KB of HTML on a single tool call can fill the agent's context window and DoS the calling agent. Bounded.
Corpus signal: covered under API4 above.
Prevention: response-size cap. Pagination with explicit budget.
LLM05: Supply Chain Vulnerabilities
LLM definition: dependency CVEs, model provenance, plugin compromise.
MCP shape: direct fit, but mostly orthogonal to MCP-specific review. We surface dependency-CVE signal under the maintenance axis. SCA tools (Dependabot, Snyk, OSV-Scanner) are the right primary tool here; SkillAudit is a complement, not a replacement. Detail: tools landscape.
Corpus signal: ~8% of our corpus had at least one open dependency-CVE at audit time.
Prevention: SCA in CI. Pin major versions. Subscribe to advisories.
LLM06: Sensitive Information Disclosure
LLM definition: the LLM (or its plugins) leaks sensitive data — secrets, PII, internal addresses.
MCP shape: direct fit, this is our credential-exposure axis. The most common pattern is environment-variable secrets read into tool responses (38% of corpus). Tied to the API2 broken-auth case above. Deepest illustration: the redirect-leaks-token pattern in anatomy of a credential leak.
Corpus signal: 38% as cited; the dominant credential class.
Prevention: never read secrets into response paths; strip Authorization on cross-host redirect; PII filter on response if applicable.
LLM07: Insecure Plugin Design
LLM definition: plugins (read: MCP servers) accept untrusted input as parameters and lack input validation, output validation, or authorization.
MCP shape: this is the MCP server review. LLM07 is essentially the OWASP shorthand for "audit your MCP server." The whole six-axis surface — security, permissions, credentials, maintenance, compatibility, docs — is what closing LLM07 looks like in practice.
Corpus signal: 42% of corpus earned an F under our methodology, which is roughly the LLM07 fail rate at the population level.
Prevention: the rest of this page.
LLM08: Excessive Agency
LLM definition: the LLM has more permissions than the task requires.
MCP shape: direct fit, our permissions-hygiene axis. Manifests as: registered tools that are never invoked; tool descriptions that read more like "do anything" than "do this specific thing"; servers that take a single broad token (e.g., a GitHub token with repo scope) when narrower scopes would do.
Corpus signal: ~25% of corpus has at least one over-broad-scope finding.
Prevention: declare narrowly. Use the narrowest upstream scope. Diff declared vs. used and remove the gap.
LLM09: Overreliance
LLM definition: users trust LLM output without verification.
MCP shape: doesn't translate at the server layer. It's a UX and governance concern at the agent layer. We don't review for this.
LLM10: Model Theft
LLM definition: attacker exfiltrates model weights or extracts proprietary models via querying.
MCP shape: doesn't translate. MCP servers don't host models.
The MCP-specific surface that neither list captures
Three threat shapes are central to MCP review and don't have a clean home in either OWASP list:
- Credential echo into tool response. Distinct from API2 (broken auth) because the credential is correctly authenticated upstream — the failure is that it gets reflected back to the LLM/user. LLM06 (Sensitive Information Disclosure) is the closest, but it's broader. We name this its own finding class.
- Permission scope vs. handler implementation drift. Tools registered in the server's manifest that the implementation never actually calls. LLM08 (Excessive Agency) is the closest, but excessive agency is an agent-design concern; this is a server-implementation concern. Distinct enough that we audit it as its own axis.
- Client compatibility drift. Servers that work on Claude Code but break on Cursor or Windsurf, often due to a protocol-version assumption. Not a security concern per se, but it shapes the "is this safe to adopt" decision because a server that breaks under one client's MCP version may have unspecified behavior under others.
Calling these out under their own names — rather than forcing them into LLM07 or API8 — is part of why the MCP-aware review category exists at all. Our methodology documents each as a first-class axis.
Coverage matrix: OWASP categories vs. SkillAudit axes
| OWASP category | Maps to MCP? | SkillAudit axis | Corpus rate |
|---|---|---|---|
| API1 BOLA | Stretches | Security (path traversal) | ~5% |
| API2 Broken Authentication | Direct | Credential exposure | 38% |
| API3 Property-Level Auth | Stretches | Security (DB-shape) | ~3% |
| API4 Unrestricted Resource Consumption | Direct | Security (DoS sub-class) | ~12% |
| API5 BFLA | No | — | n/a |
| API6 Sensitive Business Flows | No (upstream) | — | n/a |
| API7 SSRF | Direct | Security (primary) | 50% |
| API8 Security Misconfiguration | Direct | Security + credential | ~18% |
| API9 Improper Inventory | Direct | Maintenance | ~9% |
| API10 Unsafe API Consumption | Direct | Prompt-injection probe | ~22% |
| LLM01 Prompt Injection | Direct | Prompt-injection probe | ~30% |
| LLM02 Insecure Output Handling | Partial | Documentation | ~5% marked |
| LLM03 Training Data Poisoning | No | — | n/a |
| LLM04 Model DoS | Partial | Security (DoS sub-class) | covered by API4 |
| LLM05 Supply Chain | Direct | Maintenance | ~8% |
| LLM06 Sensitive Info Disclosure | Direct | Credential exposure | 38% |
| LLM07 Insecure Plugin Design | Direct (this IS the review) | All six axes | 42% F-grade |
| LLM08 Excessive Agency | Direct | Permissions hygiene | ~25% |
| LLM09 Overreliance | No (agent layer) | — | n/a |
| LLM10 Model Theft | No | — | n/a |
"Corpus rate" = share of the 101-server corpus showing at least one finding in this class under SkillAudit's methodology v0.3. See the corpus paper for full distributions.
How to use this on your own server
- Skim the table. The "Direct" rows are where OWASP's vocabulary fits cleanly onto your MCP server. Use those names in your README's security section, your incident-response playbook, and your release notes — security buyers recognize them.
- Run an audit. SkillAudit's six-axis review covers all the "Direct" rows automatically and produces an A–F grade plus per-axis findings. Free tier covers public repos. Run one on your own GitHub URL.
- Fix the highest-rate classes first. If you have an SSRF, fix it before anything else — half the F-grades in the corpus are SSRF-driven. Credential-echo next. Resource-consumption third.
- Write a security policy that references both lists. Map each category to a control objective in your own framework. The Team plan's policy export does this for you, mapped to the OWASP categories above. Detail: install-gate policy.
Related questions
Is there an OWASP-published MCP-specific top 10 yet?
Not as of mid-2026. The OWASP GenAI working group is the closest active body; their LLM Top 10 (2025) explicitly addresses plugins under LLM07, which is the nearest official concept. We expect MCP-specific guidance to land in a future revision; until then, this mapping is what we use internally.
Should I just rely on OWASP's API Top 10 and skip the MCP-specific work?
The API Top 10 is necessary but not sufficient. Six of its categories map cleanly, but the credential-echo, prompt-injection-of-tool-I/O, and permissions-drift threats are MCP-specific and won't show up in an API-shaped review. A reviewer who only ran OWASP API would have given several F-grade servers in our corpus a pass.
Why do you LLM-probe for prompt injection? Isn't that better caught statically?
Static analysis can flag obvious patterns (free-text passthrough, raw HTML in responses) but cannot prove the absence of an injection vector. The LLM-assisted probe is honest about this — it tries known injection patterns against the actual tool surface and reports what landed. Detail: calibration delta.
Does running OWASP ZAP or Burp on an MCP server help?
Marginally. ZAP and Burp expect HTTP API shapes. MCP runs over stdio or SSE typically; even when over HTTP, the surface is JSON-RPC tool calls, not REST endpoints. You can wrap an MCP server in an HTTP transport and probe it, but you'll mostly catch transport-layer findings (CORS, headers) — not the tool-handler classes that dominate our corpus.
Where can I cite OWASP from in my own MCP server's README?
The two stable URLs are OWASP API Security Top 10 (2023) and OWASP Top 10 for LLM Applications. Reference LLM07 specifically when discussing your security posture; it's the term reviewers and buyers will recognize fastest in MCP context.
Further reading
- MCP server security best practices — the practical playbook drawn from the A-grade cohort.
- MCP server security risks — enumerated — the full threat-class list with corpus rates.
- MCP server security review — what one looks like — the buyer's guide to reviews.
- MCP server security tools landscape — where SCA, SAST, Inspector, and MCP-aware scanners fit.
- The state of MCP server security, 2026 — methodology and grade distribution across all 101 servers.
- Anatomy of a credential leak — the deepest worked example of API2 / LLM06 in MCP shape.
- Anatomy of an A-grade MCP server — the patterns shared by the 19 As.
- Minimum-grade install-gate policy — operationalizing OWASP+ in CI.
- Engine v0.3 methodology — the rule set, taint paths, calibration set, and known limits.
- OWASP API Security Top 10 (2023) — official
- OWASP Top 10 for LLM Applications — official