Threat · parameters
MCP Injection Attacks: SQL, Command, Path and SSRF
These are not new weaknesses. They are the oldest weaknesses in the catalogue, reached through a new input source — one that will construct whatever string a document tells it to.
The short answer
MCP injection attacks occur when a model-supplied tool parameter reaches an interpreter: a SQL engine, a shell, a filesystem path, an HTTP client or a template renderer. The weaknesses are the classic ones, but model-supplied input is more dangerous than user input because content the agent reads can specify the payload, and because unbounded string parameters are common in tool schemas. The defence is schema constraint plus parameterisation, applied before the value reaches the interpreter. Five injection classes, the schema patterns that invite them, SSRF specifics, and how to test in an afternoon.
Key takeaways
- 01The model is not the attacker. It is the delivery mechanism — injected content specifies the payload and the model constructs it faithfully.
- 02An unbounded string parameter reaching an interpreter is a code-execution tool, whatever the tool is named.
- 03Schema constraint is the cheapest control: an enum cannot carry a payload. Narrow the type before writing a validator.
- 04Parameterise at the interpreter. Escaping is a fallback and it has lost before.
- 05SSRF is the most under-considered class: a URL parameter makes the server a proxy into your internal network.
- 06Score tools by what their schema permits, not by their name.
search_documentswith a free-string query may be a query-language execution tool.
Why model-supplied input is worse than user input
Application security has thirty years of practice at treating user input as hostile. The instinct is right and most of the techniques transfer. Three differences make the agent case harder rather than merely equivalent.
The input source can be argued into anything. A human attacker has to reach your input field. An attacker who can place text where an agent will read it — a support ticket, a shared document, a web page — can specify a payload and have the model construct it. The model is not compromised; it is doing what it was asked, by content it had no basis to distrust.
Tool schemas are permissive by convention. Tools are written to be useful to a model, and free-string parameters are more useful than enums. A schema that would never pass review on a public API is normal in an MCP server, because the author was thinking about capability rather than about a hostile caller.
The call looks legitimate. There is no unusual endpoint, no malformed request, no authentication anomaly. An entitled agent calls a permitted tool with a syntactically valid parameter. Every layer above the interpreter sees nothing wrong.
So the control has to sit at the parameter, and it has to be structural rather than behavioural.
Key facts
- ▸Injected content specifies the payload; the model constructs it faithfully.
- ▸Free-string parameters are conventional in MCP tools and would fail review on a public API.
- ▸Nothing above the interpreter can distinguish a malicious call from a legitimate one.
Five injection classes
Same weaknesses as always. What differs is which schema patterns make an MCP tool reachable.
| Class | Reached via | Schema pattern that invites it | CWE |
|---|---|---|---|
| SQL / query injection | A search or filter parameter concatenated into a query | query, filter, where as free strings | CWE-89 |
| OS command injection | A parameter reaching a shell, script or system call | command, args, options as strings or string arrays | CWE-78 |
| Path traversal | A filename or key used to build a filesystem or object-store path | path, filename, key with no pattern constraint | CWE-22 |
| SSRF | A URL the server fetches on the caller’s behalf | url, endpoint, webhook, callback | CWE-918 |
| Template / expression injection | A value rendered into a template or evaluated as an expression | template, expression, formula | CWE-1336 |
A useful heuristic when reviewing a third-party server: look at the parameter names before the tool names. A tool called get_report with a filter parameter typed as a free string is more interesting than a tool called execute_query with a bounded enum. Names describe intent; schemas describe capability.
Fix the schema before writing a validator
The instinct is to validate input. Better first move: narrow the type so the dangerous value cannot be expressed. A validator is code that can have a bug; a schema constraint is a structural property.
In order of strength.
Enumerate
If the set of valid values is finite, declare it. An enum cannot carry a payload. This is available far more often than teams assume — sort fields, status values, report names, regions.
The single highest-value change available. Every free-string parameter that becomes an enum removes an entire class of concern permanently, with no runtime cost.
Type precisely
Integers where a number is meant, with minimum and maximum. Booleans where a flag is meant. Dates as format: date. A typed parameter cannot carry a string payload at all.
Pattern and length
Where a string is genuinely required, constrain it: a regex for identifiers, a maximum length, a character class. A 40-character alphanumeric identifier field is a poor injection vector.
Length limits matter more than they look. Most payloads need room, and a 64-character cap eliminates a large fraction of them without affecting legitimate use.
Structure instead of string
Replace a free-text query with a structured object: {field: enum, operator: enum, value: typed}. The tool composes the query itself from validated parts, and the caller never supplies syntax.
More work, and it is the right answer for any search or filter tool that reaches a real query engine. It also makes the tool easier for a model to use correctly, which is a rare alignment of security and usability.
Then validate
With the schema as tight as it can be, remaining validation is a short list of checks rather than an attempt to anticipate every payload.
Defences at the interpreter
Schema constraint reduces what can arrive. Interpreter-side defences ensure that what does arrive cannot change structure.
- 01Parameterise, always. Bound parameters for SQL, argument arrays rather than shell strings for commands, path-joining APIs that reject traversal rather than string concatenation. Parameterisation separates data from structure at the mechanism level; escaping tries to do it with string manipulation and has a losing historical record.
- 02Never invoke a shell. Where a subprocess is genuinely required, execute the binary directly with an argument array and no shell interpretation. Most command injection depends on a shell being in the path.
- 03Canonicalise then check, for paths. Resolve the path fully, then verify it is inside the permitted root. Checking before resolution is defeated by traversal sequences and symlinks.
- 04Run the interpreter with minimal privilege. A database user that can only read the three tables the tool needs bounds a successful injection to those three tables. This is the control that limits damage when the others fail.
- 05Cap results and time. A row limit and a timeout turn a successful bulk-extraction injection into a partially successful one, and make it visible in latency metrics.
Built on this thinking
Parameter policy runs outside the server
BarzelVault evaluates every parameter value against declared bounds, patterns and allow-lists before the call reaches a server — so a crafted value is refused at the enforcement point regardless of what the tool’s own validation does or does not do, with the attempted value recorded rather than clamped.
SSRF: the class nobody scores
SSRF deserves its own section because it is the one most often missed in MCP tool review, and because its consequence is unusually large: the tool becomes a proxy that reaches your internal network from a position of trust.
Any parameter the server fetches is an SSRF surface — a URL to retrieve, a webhook to call back, an image to render, a document to import, a link to preview. A model can be induced to supply an internal address by content it reads, and the server’s own network position does the rest.
Four defences, and the ordering matters.
| Defence | Why | Common mistake |
|---|---|---|
| Allow-list destinations | The only defence that holds. Enumerate permitted hosts or a permitted domain suffix | Using a blocklist — the address space is too large and too creatively expressible |
| Resolve DNS then validate the IP | Prevents a permitted hostname resolving to an internal address | Validating the hostname string and never checking what it resolves to |
| Re-validate after redirects | A permitted URL can redirect to an internal one | Following redirects with validation applied only to the original URL |
| Restrict egress at the network layer | Removes reachability regardless of application logic | Assuming application validation is sufficient |
The specific addresses to deny if you must use a denylist as a secondary layer: loopback, link-local (including cloud metadata endpoints), all private ranges, and anything resolving to your own service mesh. But treat that as defence in depth behind an allow-list, never as the primary control — encoded, shortened and redirect-chained addresses have defeated denylists consistently.
Network-layer egress restriction is the control that holds when application logic fails, and for third-party servers it is the one to insist on. A container that can only reach its one backing system cannot be a proxy into anything.
Testing for reachability
The question is not whether a tool validates input. It is whether a parameter reaches an interpreter at all — which is often unknown, particularly for third-party servers.
| Test | Method | Signal |
|---|---|---|
| Interpreter reachability | Send a syntactically distinctive but harmless value: a quote, a semicolon, a ../, a {{7*7}} | An error mentioning SQL, a shell, a path or a rendered 49 tells you what is behind the parameter |
| Length behaviour | Send a value far longer than any legitimate input | A truncation, a timeout or a stack trace indicates unbounded handling |
| Type coercion | Send a string where a number is declared, and an array where a string is declared | Acceptance means the declared schema is not enforced server-side |
| SSRF probe | Supply a URL to a host you control and watch for the callback | A callback proves the server fetches caller-supplied URLs; check the source IP for network position |
| Internal address probe | Supply a loopback and a link-local address | Any response other than a clean refusal is a finding |
| Injected-instruction end-to-end | Plant content telling the agent to call the tool with a crafted value | Confirms the whole chain, and that policy refuses it regardless of the model’s reasoning |
Run the last test at least once with the team watching. It connects two things that are usually discussed separately — that a model can be persuaded, and that a parameter reaches an interpreter — and seeing the enforcement point refuse the resulting call is what makes the case for parameter policy concrete.
What parameter defence does not cover
These controls stop a crafted value from changing an interpreter’s structure. They do nothing about a perfectly well-formed value that is simply wrong — a legitimate query for the wrong customer, a valid path to a file the agent should not read. That is an authorization question, not an injection one, and it needs entitlement design.
For third-party servers you cannot inspect the interpreter side at all. You can constrain what reaches it and restrict what it can reach, but you cannot know whether it parameterises. Assume it does not: keep the credential narrow, restrict egress, and treat the schema you can see as the only contract you have.
And schema constraint has a genuine cost in capability. A structured query object is less flexible than a free-text one, and some legitimate uses become impossible. That trade is usually worth making for anything touching a real query engine, but it is a trade rather than a free win, and pretending otherwise is how security guidance gets ignored.
Frequently asked questions
What are MCP injection attacks?
Classic injection weaknesses reached through model-supplied tool parameters: SQL and query injection, OS command injection, path traversal, SSRF and template injection. The weaknesses are old; the new element is an input source that can be argued into constructing any payload.
Why is model-supplied input more dangerous than user input?
Three reasons. Content the agent reads can specify the payload, so an attacker only needs to place text where the agent will see it. Tool schemas are permissive by convention, since free-string parameters are more useful to a model. And the resulting call looks entirely legitimate to every layer above the interpreter.
How do you tell if an MCP tool is vulnerable to injection?
Look at the parameter schemas rather than the tool names. A free-string parameter named query, filter, path, url, command or template is the signal. Then test reachability with a syntactically distinctive but harmless value and see what the error reveals.
What is the most effective defence against tool parameter injection?
Schema constraint, applied before any validation logic. An enum cannot carry a payload. Narrow the type, add patterns and length limits, and replace free-text queries with structured objects the tool composes itself — then validate what remains.
Should you escape or parameterise tool parameters?
Parameterise. Bound parameters for SQL, argument arrays rather than shell strings for commands, path-joining APIs that reject traversal. Parameterisation separates data from structure at the mechanism level; escaping attempts it with string manipulation and has a losing historical record.
Why is SSRF a particular risk for MCP tools?
Because any parameter the server fetches — a URL, a webhook, an image, a document import, a link preview — turns the server into a proxy reaching your internal network from a trusted position. A model can be induced to supply an internal address by content it reads.
How do you defend against SSRF in MCP tools?
Allow-list destinations rather than blocklisting, resolve DNS and validate the resulting IP rather than the hostname string, re-validate after every redirect, and restrict egress at the network layer so reachability is removed regardless of application logic.
What is the safest way to handle a search or filter parameter?
Replace the free-text string with a structured object of enumerated fields, enumerated operators and typed values, and have the tool compose the query itself. The caller never supplies syntax, which also makes the tool easier for a model to use correctly.
How do you limit damage if an injection succeeds?
Run the interpreter with minimal privilege — a database user that can read only the three tables the tool needs bounds the outcome to those three tables — and cap result counts and execution time so bulk extraction becomes partial and visible in latency metrics.
Can you secure a third-party MCP server against injection?
Not directly, since you cannot inspect its interpreter side. Assume it does not parameterise: constrain what reaches it through parameter policy at the enforcement point, keep its credential narrow, and restrict its network egress so a successful injection cannot reach anything.
Glossary
- Tool parameter injection
- Supplying a crafted value through an MCP tool parameter so that it is interpreted as code, a query, a path or a URL by a downstream component.
- Interpreter reachability
- Whether a tool parameter’s value ultimately reaches a component that interprets structure — the property that turns a string into a vulnerability.
- Schema constraint
- Narrowing a parameter’s declared type, format, enumeration or length so that dangerous values cannot be expressed at all.
- SSRF
- Server-side request forgery: inducing a server to make an HTTP request to a location of the attacker’s choosing, typically reaching internal services.
- Parameterisation
- Passing values to an interpreter through a binding mechanism that keeps data separate from structure, rather than by string concatenation.
Sources and further reading
The weakness classes are defined by CWE and OWASP, which are authoritative. What is specific to this article is how model-supplied parameters change the threat model and which schema patterns make MCP tools reachable.
- 01 · MITRECWE — Common Weakness Enumeration ↗Named weakness classes — injection, path traversal, SSRF — that reappear when a model supplies the parameters.
- 02 · MITRECWE-89 — SQL Injection ↗The canonical description of the weakness a model-supplied parameter can reach.
- 03 · MITRECWE-78 — OS Command Injection ↗What happens when an unbounded string parameter reaches a shell.
- 04 · MITRECWE-918 — Server-Side Request Forgery ↗Why a URL parameter on a tool is an internal-network reachability question.
- 05 · OWASPOWASP Application Security Verification Standard ↗Input-validation, authorization and logging requirements restated here in MCP terms.
- 06 · OWASP GenAI Security ProjectOWASP GenAI LLM Top 10 (2026) ↗Consensus risk list; excessive agency and prompt injection are the entries governance exists to bound.
- 07 · JSON SchemaJSON Schema Specification ↗How tool parameter contracts are expressed, and what a validator can enforce.
- 08 · MCP projectModel Context Protocol — specification ↗Normative source for tool schemas, capability negotiation and the authorization model.
Last reviewed 2 September 2026. External links open in a new tab; we do not control their content.
Cite this article
Alex, M. (2026). MCP Injection Attacks: SQL, Command, Path and SSRF. Real Biz Digital. https://realbizdigital.net/insights/mcp-injection-attacks/
Try the mechanics on a live server
To watch a real tools/list response before you point a client at anything that governs production — Barzel Scripture Intelligence is free and public at scripture-intelligence-server.mcpize.run: no signup, no key, 54 tools. Setup is in the reference.
Buy it on the marketplace
BarzelVault is the pre-execution decision point, sold as a running product
Nine tools, 12 static resources, 3 resource templates and 9 prompts. Four deterministic outcomes — allow, deny, dry-run, require approval — with approval workflow, hash-chained audit and guardrail data protection. Streamable HTTP, JSON-RPC 2.0.
| Plan | Price | Included | Right for |
|---|---|---|---|
| Dev | Free | 10,000 policy decisions/mo · 9 tools, 4 outcomes, hash-chained audit | A first regulated workflow: one agent, one high-consequence system |
| Team | $199/mo | 75,000 decisions/mo · approval workflow, spend and action limits | Several agents acting on money, records or customer-visible systems |
| Business | $799/mo | 750,000 decisions/mo · exact HTTPS execution, credential isolation, emergency controls | Enterprise-wide pre-execution enforcement with audit obligations |
| Enterprise | $3,999/mo | 5,000,000 decisions/mo · everything in Business, scaled | Group-wide rollout across many teams and systems |
Sold on the MCPize marketplace · prices as listed 2 Sep 2026 · the listing is authoritative
Written by
Mark Alex
Founder of Real Biz Digital and architect of the Barzel ecosystem — five MCP servers published and callable in public. Software developer, technology entrepreneur and mechatronics engineer, working across AI agent governance, MCP security, AI infrastructure, FinOps and intelligent operations.