Skip to content
Agentic Control Plane

4,500 MCP Servers, 7,840 Tools, Zero Input Validation. Here's the Attack Surface.

David Crowe · · 6 min read
security-research mcp supply-chain

MCP tools define input schemas. An LLM reads the schema, generates the parameters, and the server executes the call. But schemas aren’t validation. The schema says “this parameter is a string.” It doesn’t say “this string must not contain ../ or ; rm -rf /.”

I parsed the tool definitions of 8,216 MCP servers to map the actual attack surface.


How I did it

I pulled tool definitions from the ToolSDK MCP Registry, which indexes 4,548 servers with 8,010 tool definitions across 30 categories. Each tool has a name, description, and (sometimes) an input schema.

For tools with schemas, I checked every string parameter for validation constraints: enums, patterns, format specifications, maxLength. A string parameter with none of these is a freeform input — the tool will accept whatever the LLM sends.

For tools without detailed schemas (the majority), I analyzed tool names and descriptions for high-risk patterns. A tool called execute_command that accepts a command parameter is a command injection surface regardless of whether the schema is documented.

I categorized high-risk parameters into six injection categories:

Category Pattern What it enables
SQL injection sql, query, statement, where_clause Direct database manipulation
Path traversal path, file_path, directory, filename Filesystem escape
Command injection command, cmd, shell, exec, script Arbitrary code execution
SSRF url, uri, endpoint, host, webhook Internal network probing
XSS html, template, content, body, message Content injection
Code injection code, expression, eval, formula, regex Runtime code execution

The numbers

7,840 tools across 8,216 servers. 4,512 high-risk input parameters detected across 2,432 servers (29.6% of the ecosystem).

Risk breakdown

Category Flagged Parameters What these tools do
XSS / content injection 1,650 Accept HTML, templates, message bodies — content the user or agent generates
SSRF 831 Accept URLs, endpoints, webhook addresses — anywhere the server will make outbound requests
Code injection 740 Accept code, expressions, regex, formulas — input that gets evaluated
SQL injection 566 Accept raw SQL, query strings, filter expressions — direct database input
Command injection 368 Accept shell commands, scripts, terminal input — system-level execution
Path traversal 357 Accept file paths, directory names — filesystem navigation

The most common dangerous tool patterns:

Tool pattern Occurrences
search / search_* 14+
execute_command / run_command 6+
send_message / add_comment 5+
run_code / eval 5+
search_files / search_codebase 5+
browser_navigate 4+
FileWriteOrEdit 4+

The worst offenders

Servers with the most high-risk input surfaces:

Server High-Risk Params
hostinger-api-mcp 119
@configcat/mcp-server 89
Graphlit 87
IT Tools MCP 58
@smartbear/mcp 50
Tree Sitter MCP Server 34
XcodeBuild MCP 32
Phone MCP 30

These aren’t necessarily vulnerable — a server can accept a query parameter and sanitize it internally. But the schema doesn’t tell you that. From the outside, the only contract is “string.” What happens after the string arrives is implementation-dependent and undocumented.

Why this matters now

In February 2026, researchers cataloged 30+ CVEs in MCP servers within 60 days. 82% involved path traversal. These weren’t theoretical — they were real exploits in real servers that people were running.

The attack path is straightforward:

  1. An agent connects to an MCP server
  2. The server exposes a tool that accepts a file path
  3. A prompt injection (or just a careless LLM generation) sends ../../etc/passwd
  4. The server reads or writes the file because it trusted the input

This is the same class of vulnerability that web apps solved twenty years ago with input validation, parameterized queries, and allowlists. MCP servers are reliving the early 2000s.

The difference: in a web app, the attacker is a human crafting malicious input. In an MCP context, the attacker can be a prompt injection in any upstream data source. The LLM reads a malicious instruction embedded in a document, a web page, or a previous tool result, and faithfully passes it as a parameter to the next tool call.

This is indirect prompt injection meeting a validation-free attack surface. The LLM is the unwitting vector. The MCP server is the target. And nothing in between is checking the input.

The MCP spec doesn’t help

The MCP specification defines tool input schemas using JSON Schema. That’s a description format, not a validation framework. A server can declare that a parameter is a string — but JSON Schema’s validation keywords (pattern, format, enum, maxLength) are optional and rarely used.

Looking at the tool definitions in ToolSDK: of 8,010 tools, those that include input schemas almost never use constraining keywords. The schema says “type: string” and stops there. It’s a hint for the LLM about what to generate, not a contract about what the server will accept.

This means:

  • The LLM has no constraints beyond the parameter name and description
  • The server receives whatever the LLM generates
  • Validation — if it exists — is ad hoc, per-server, undocumented

What deny-by-default validation looks like

The fix isn’t asking every MCP server author to implement input validation. There are 8,000+ servers and the ecosystem is growing. The fix is validating at a layer that sits in front of all of them.

A control plane that intercepts every tool call can:

  1. Parse the tool’s input schema and enforce constraints the schema should have specified — regex patterns for paths, allowlists for URLs, parameterization for SQL
  2. Apply category-specific rules — file path parameters get ../ stripping, SQL parameters get parameterization, URLs get allowlist checks
  3. Detect injection patterns — the same patterns that show up in CVEs (path traversal sequences, shell metacharacters, SQL injection markers) get caught before they reach the server
  4. Log every parameter value for forensic analysis — even if a novel injection technique gets through, you have the audit trail

This is the validatabl pattern. The server doesn’t need to validate. The control plane does.


Methodology

Tool definitions from ToolSDK MCP Registry (4,548 servers, 8,010 tools). High-risk parameter detection via regex matching on tool names, descriptions, and schema property names. Server descriptions analyzed for servers without explicit tool definitions.

This is static analysis of metadata. It identifies the surface area — tools that accept high-risk input types. It does not prove that any specific server is vulnerable. A server that accepts a path parameter may sanitize it internally. We can’t tell from the schema.

What we can tell: 2,432 servers expose input surfaces where a single unsanitized parameter is a CVE. The question is whether you want to trust each server’s internal validation — or enforce it at the control plane.

Read the reference architecture → · Get started free →

Share: Twitter LinkedIn
Related posts

← back to blog