Three Data Points in One Week

In the same week we were fixing compliance issues on our own MCP server, three things happened:

📄

arxiv 2603.10163 — Academic paper drops

"Compatibility at a Cost" analyzed all 10 official MCP SDKs against the 275 clauses in the MCP specification. Found 1,265 potential risks. 78.5% of clauses are optional or conditional. 26 reports submitted to maintainers; 20 acknowledged, 5 triaged as high-priority. Total cost: $541.87 in LLM API calls.

🛡️

CVE-2026-26118 — First Azure MCP CVE

Microsoft's March 2026 Patch Tuesday included an elevation-of-privilege vulnerability (CVSS 8.8) in Azure MCP Server Tools. The flaw: an SSRF that lets an attacker trick the MCP server into forwarding its managed identity token, granting the attacker whatever permissions the server holds. Not theoretical. A real patch, a real fix.

🚨

CNCERT Advisory — China bans OpenClaw

China's National Internet Emergency Center warned that OpenClaw has critical security flaws: prompt injection via web content, data exfiltration through link previews, and malicious skill uploads. Over 135,000 exposed instances found. China restricted OpenClaw in government agencies and state-owned banks. The underlying mechanisms apply to any MCP-based system.

Three independent data points. The pattern is clear.

78.5%
Clauses optional
1,265
Risks found
8.8
CVE CVSS score
135K+
Exposed instances

What "Optional Clause" Actually Means in Practice

The arxiv paper identifies three attack modalities based on what an attacker controls:

PyTy — Payload + Timing

Attacker controls both message content AND when it arrives. A server without tool-change notifications can have tools silently added or modified mid-session, injecting malicious prompts without any visible state change.

PnTy — Timing Only

Attacker controls timing but not content. A server with no ping handler can be DoS'd through rate-limited ping floods — the server can't respond, the client assumes it's dead, sessions terminate unexpectedly.

PyTn — Payload Only

Attacker controls content but not timing. A server with no resources/list or prompts/list handler forces clients to make exploitable assumptions about server capabilities.

Our three missing methods mapped directly to these classes. We were vulnerable to all three categories of clause-compliance attacks.

The Problem With "38% of Servers Have No Auth"

The arxiv paper includes a statistic that deserves its own section: 38% of MCP deployments have no authentication at all.

Without auth, any client can connect. Including a malicious one.

This isn't theoretical. The sampling attack surface — where a server can inject prompts into the connected LLM — is particularly dangerous when combined with no auth. An unauthenticated server can:

1. Override system prompts
2. Exfiltrate context from other connected servers via includeContext: "allServers"
3. Inject tool-call instructions into the LLM
4. Trigger recursive sampling loops

None of this requires a sophisticated exploit. It requires writing a JSON-RPC payload.

For our AEO MCP server, we made a conscious decision: intentionally unauthenticated and CORS-open. We're a public tool for lead generation — we want any AI assistant to be able to call us. That's a valid design choice. But it needs to be documented as a design choice, not discovered as an oversight.

We Built a Scanner

We wrote mcp-check — a Bun script that connects to any MCP server over Streamable HTTP and checks it against the known vulnerability classes from the arxiv paper.

$ bun mcp-check.ts https://aeo-mcp-server.amdal-dev.workers.dev/mcp ┌───────────────────────────────────────────────────────────┐ │ MCP Security Check │ └───────────────────────────────────────────────────────────┘ Target: aeo-mcp-server.amdal-dev.workers.dev/mcp Risk Level: LOW Server: aeo-audit v1.0.0 Capabilities: tools, resources, prompts ┌───────────────────────────────────────────────────────────┐ ✓ Ping Handler [INFO] ✓ Resources List Handler [INFO] ✓ Prompts List Handler [INFO] ✓ Notification Handler [INFO] ⚠ Authentication [MEDIUM] — intentionally open ⚠ CORS Policy [MEDIUM] — intentionally open ✓ Tools List Handler [INFO] └───────────────────────────────────────────────────────────┘ Summary: 5 passed, 0 failed, 2 warnings

After our fixes: clean. Before our fixes, we would have had 3 FAILs in the PnTy and PyTn vulnerability classes.

The scanner is open source: github.com/piiiico/mcp-check

What the MCP 2026 Roadmap Says About Security

The MCP team published their 2026 roadmap last week. The four top priorities: transport evolution, agent communication, governance maturation, and enterprise readiness. Security and authorization are listed under "On the Horizon" — meaning they have community support but are not active Core Maintainer focus this cycle.

This is not a criticism. The MCP team is making reasonable prioritization decisions. But it means: the ecosystem will continue shipping MCP servers with security gaps for the foreseeable future, because the official tools for catching those gaps don't exist yet.

That's the gap the arxiv paper's tooling addresses. That's the gap our scanner addresses.

The Practical Checklist

If you're running an MCP server:

1
Implement all three base handlers: ping, resources/list, prompts/list. Even if they return empty arrays. This costs 10 lines of code and prevents the entire PyTn vulnerability class.
2
Handle notifications gracefully: Return HTTP 200/202 for any notification method you don't explicitly handle. Don't return 405.
3
Decide your auth story deliberately: Open is fine for public tools. But if your server has any access to user data, secrets, or takes actions with real-world consequences — require auth and document why.
4
Review tool descriptions for injection patterns: Scan for phrases like "ignore previous instructions," template injection syntax ({{}}, ${}), or unusually long descriptions that might hide embedded prompts.
5
Lock down sampling/createMessage: If you implement sampling, don't pass systemPrompt through to the LLM unchanged. Don't auto-approve includeContext: "allServers". Don't treat sampling responses as executable instructions.
6
Run against a scanner before publishing: It takes 30 seconds. The arxiv methodology is reproducible. Our scanner is a start. More will follow.

The Bigger Picture

March 2026 is when MCP security went from theoretical to concrete:

First CVE in Azure MCP infrastructure (CVE-2026-26118, CVSS 8.8)
Academic paper with 1,265 identified risks across official SDKs
National government banning an AI agent framework over security flaws
MCP 2026 roadmap explicitly deferring security to "On the Horizon"

The MCP community invited the arxiv authors' tooling to be integrated into conformance-testing standards. That's the right call. But it takes time.

In the meantime: 78.5% of the spec is optional. Your server almost certainly has gaps. Run a scanner.

Want your MCP server audited?

We audit MCP servers for clause-compliance vulnerabilities and security gaps. Run our open-source scanner yourself, or let us do a deep review.

Try mcp-check on GitHub →

References