Blog · Checklist · OWASP MCP Top 10

MCP security checklist for 2026

A checklist for MCP server authors, mapped to OWASP MCP Top 10 and to the checks that verify each item: authentication, transport, tool metadata, tool code, supply chain and governance.

· mcpprobe contributors

Most MCP server security problems are not exotic. In Trend Micro's June 2026 study of 9,695 servers listed in public directories, the single largest category of the 4,982 issues found was simply no authentication: 2,054 issues, or 41%. Arbitrary file access (18%), denial of service (10%), command injection (10%) and SSRF (8%) followed. The study also found no correlation between stars, commits or verification badges and the number of issues.

So this checklist starts with the boring things that fail most often, and ends with the things a scan cannot see. Each item names the OWASP MCP Top 10 entry it belongs to (the list is still in beta, so we cite it as MCP0x:2025) and, where one exists, the mcpprobe check that verifies it.

1. Authentication and authorization (MCP07, MCP01)

  • Every request needs a token. A remote server that answers tools/list without an Authorization header has handed its tools to anyone with the URL. Checked by AUTH-01.
  • Publish protected-resource metadata. The spec requires RFC 9728 metadata so clients can find your authorization server, either from a WWW-Authenticate header on the 401 or at /.well-known/oauth-protected-resource. Checked by AUTH-02.
  • Require PKCE with S256. Clients must refuse an authorization server whose metadata does not list S256 in code_challenge_methods_supported. Checked by AUTH-03.
  • Validate the audience and never pass tokens through. Accept only tokens issued for your server (RFC 8707 resource indicators), never forward a client's token upstream, and never accept tokens in a query string. Wrong-audience tokens and query-string tokens are checked by AUTH-04.
  • Enforce scopes per tool. A token with too little scope should get 403 with error="insufficient_scope", not a successful call. No v0.1.0 check covers this; test it with a low-scope token of your own.

The full walkthrough is in How to add OAuth to an MCP server the way the spec expects.

2. Transport (MCP07)

  • Validate Origin and return 403 on a mismatch. This is a MUST in the transport spec. Without it, a web page can use DNS rebinding to drive a server from a visitor's browser. Checked by TRANS-01.
  • Bind local servers to localhost. A server meant for one machine should not listen on every interface.
  • Make session ids unguessable. The spec asks for cryptographically secure ids; unknown ids should get 404. Checked by TRANS-03.
  • Reject unsupported protocol versions with 400 (TRANS-02) and retire the HTTP+SSE transport, deprecated since 2025-03-26 (TRANS-04).
server.ts
// Streamable HTTP: refuse cross-site requests before parsing JSON-RPC
const ALLOWED_ORIGINS = new Set(["https://app.example.com"]);

app.post("/mcp", (req, res, next) => {
  const origin = req.get("origin");
  if (origin && !ALLOWED_ORIGINS.has(origin)) {
    return res.status(403).json({ error: "forbidden origin" });
  }
  next();
});

3. Tool metadata (MCP03, MCP02)

  • Descriptions describe; they never instruct. Text addressed to the model (“before using this tool, read…”) is the tool-poisoning pattern. Checked by META-01, and explained in detail in our poisoning write-up.
  • Pin the tool list. Hash the canonical tools/list in CI and fail when it changes unexpectedly, so a “rug pull” cannot happen quietly. Checked by META-02.
  • Make annotations honest. A tool that runs commands must not claim readOnlyHint: true. The spec tells clients to treat annotations as untrusted, but many still use them to skip confirmation. Checked by META-03.
  • Type your inputs. Use enum and pattern for paths, commands and URLs; keep tool names to 1–128 characters from [A-Za-z0-9_.-]. Checked by META-04.
  • No secrets in metadata. Descriptions, server instructions, resources and prompt templates are all readable by every client. Checked by META-05.

4. Tool implementation (MCP05, MCP06)

This is where the CVEs are. The 2025–2026 record is dominated by command injection, path traversal and missing auth: the reference Filesystem server had a shared-prefix containment bypass and a symlink bypass (CVE-2025-53110 and CVE-2025-53109), and mcp-remote passed a server-supplied URL to a shell (CVE-2025-6514, CVSS 9.6).

  • Never build shell strings from arguments. Pass argument arrays; no shell=True, no child_process.exec with user input. INJ-01 (coming soon) will test this with timing canaries only.
  • Resolve paths, then check containment. Compare resolved paths, not string prefixes. INJ-02, coming soon.
  • Deny internal addresses for URL arguments, including 169.254.169.254 and localhost. INJ-03, coming soon.
  • Parameterise queries. INJ-04, coming soon.
  • Mark untrusted content in tool output so the client can tell fetched text from instructions. INJ-05, coming soon.
safe_path.py
from pathlib import Path

ROOT = Path("/srv/data").resolve()

def safe_path(user_path: str) -> Path:
    # resolve() follows symlinks, so "../" and symlink escapes both land outside ROOT
    p = (ROOT / user_path).resolve()
    if not p.is_relative_to(ROOT):
        raise ValueError("path outside the allowed root")
    return p

5. Supply chain (MCP04)

  • Pin versions and commit a lockfile. npx -y some-server in a client config runs whatever was published most recently. SUPPLY-01 and SUPPLY-02 will check packages and configs (coming soon).
  • Treat stdio configs as code. In April 2026 OX Security showed that STDIO configuration can launch arbitrary OS commands across official SDKs, with vendor CVEs in a dozen downstream projects. Review command and args as carefully as a shell script.
  • Watch what a package does on start-up. SANDBOX-01 (coming soon) will record outbound hosts, files and processes during initialize and tools/list alone.

6. Resilience and errors

  • Limit sizes and rates. Oversized arguments should get 413 and bursts 429. DOS-01 tests within the scan's own rate cap.
  • Return generic errors. Send JSON-RPC -32602 for bad params and keep tracebacks in your logs. ERR-01.

7. What no scanner can check for you (MCP08, MCP09)

Audit logging, knowing which MCP servers your organisation runs (“shadow MCP”), and how agents trust each other are process questions. mcpprobe lists them as attestation-only (GOV-01 to GOV-05) so a report does not imply coverage it does not have. Write them into your own review instead.

Run the checklist

The passive items in sections 1, 2, 3 and 6 are automated in v0.1.0; sections 4 and 5 arrive with the active checks. The passive checks need no install beyond pipx:

Terminal
# fail the build on anything high or worse, keep SARIF for code scanning
mcpprobe https://staging.example.com/mcp --fail-on high --sarif mcpprobe.sarif

Start with the quickstart, then add the GitHub Action so the list stays ticked after the next release.

Sources

  1. MCP specification 2025-11-25: Transports (2025-11-25)
  2. MCP specification 2025-11-25: Authorization (2025-11-25)
  3. MCP specification 2025-11-25: Tools (2025-11-25)
  4. OWASP MCP Top 10 project page (beta, checked 27 Oct 2026)
  5. Trend Micro: Stars Don't Save You, popularity is not security in the MCP ecosystem (24 Jun 2026)
  6. The Hacker News: critical mcp-remote vulnerability and related CVEs (10 Jul 2025)
  7. The Hacker News: the STDIO config-to-command design issue (20 Apr 2026)