Prompt Injection Through MCP Tool Results

MCP tool results can carry hostile instructions inside ordinary asset data. Treat every result as untrusted input, expose only necessary tools, use scoped short-lived credentials, require human approval for irreversible actions, and log every call’s arguments and result. Pattern matching cannot reliably stop an attacker who can continually rewrite the payload.
Tool results are untrusted input
Prompt injection through an MCP tool result happens when data returned by a tool contains text that the model interprets as an instruction. The text may look like ordinary asset data, but it attempts to redirect the model toward an action the user or developer did not request.
A tool result is untrusted input. Asset descriptions, filenames, tags, and metadata are written by users and arrive in the model’s context with the same standing as the developer’s instructions. A model can use both to decide what to do next; the fact that one string came from a tool does not make its imperative language harmless.
That boundary matters whenever an MCP server retrieves content that somebody outside the current conversation could have written. The server may faithfully return the stored value, and the client may faithfully place it in context, while the model still makes the wrong decision about whether that value is data or an instruction. No component has to be compromised for the injection to arrive.
The practical rule is to treat every returned string as potentially adversarial, including values that appear too small or routine to merit review. A trusted MCP server can return untrusted records. Authentication tells the client which server answered; it does not establish that every filename, description, tag, caption, or metadata value held by that server is safe to obey.
The current MCP specification defines the protocol surface, but a protocol connection does not turn retrieved content into trusted instructions. The application using that connection remains responsible for deciding which tools are available, what authority their credentials carry, and which proposed calls require approval.
The instruction hides in an ordinary field
The classic shape is an instruction hidden in a field nobody reads: an alt text or caption that tells the model to call a different tool with different arguments. The visible task may be to inspect, transform, catalogue, or describe an asset. The returned record supplies the asset fields, and one field attempts to replace that task with another.
For example, the user may ask the assistant to find an image. A matching record can contain a caption that tells the model to ignore the request and invoke a deletion or publishing tool. The caption does not need to alter the image or break the MCP server. It only needs to be included in the result that the model reads before choosing its next tool call.
This is why asset operations deserve particular care. An Asset Management MCP server and its exposed operations can put user-authored descriptions, filenames, tags, and metadata into the same working context used to select subsequent actions. The dangerous field may be incidental to the user’s request: a filename returned beside an identifier, alt text returned for accessibility work, or a tag returned during search.
Structured fields do not remove the problem. A schema can distinguish a caption from a tool argument, but the model still receives the caption’s text. Defining structured metadata fields through an MCP server improves validation and makes provenance clearer; it does not make the values trustworthy instructions.
The payload also need not announce itself as an attack. It can be phrased as a correction, a prerequisite, an administrative note, or a request to use different arguments. The relevant fact is not how suspicious the prose looks. It is that a user-authored field is trying to influence control flow outside the purpose for which that field was retrieved.
Restrict the tools the connection advertises
Restricting the advertised tool list is the most effective control available, because an instruction to delete cannot be followed by a connection that never advertised deletion. The model may accept the hostile instruction, but it cannot select an absent tool through that connection.
The restriction must follow the task. A read-only asset search does not need deletion, replacement, publication, configuration, or credential-management operations. A metadata update does not automatically need access to the whole asset-management surface. The useful question is not whether an operator might need a tool at some point; it is whether this run needs the tool before the connection ends.
This control works on capability rather than language. It does not have to recognise the injected sentence, determine who wrote it, or decide whether it is malicious. It simply removes actions that are outside the current task. That is why the boundary survives new phrasing and unfamiliar payloads.
Tool restriction also prevents a broad MCP server from becoming a broad model capability by accident. A server may implement read, write, delete, configuration, and workflow operations for legitimate reasons. The client does not have to advertise all of them in every session. The detailed design question is covered in restricting which tools an MCP server exposes.
Argument validation still matters for every tool that remains. A narrowly exposed update tool can be abused if it accepts a wider target or operation than the task requires. The client or server should reject arguments outside the allowed shape rather than asking the model to remember the boundary. Guidance for defining and validating MCP prompt arguments applies the same principle at the input boundary: encode the permitted shape where software can enforce it.
Restriction does have a concrete cost. Separate task-scoped connections or tool sets require more configuration than one permanent connection advertising everything. A user may also have to start a different workflow when the requested task genuinely expands. That friction is the mechanism working: new authority becomes an explicit change instead of an accidental consequence of text found in a tool result.
Bind credentials to the smallest useful authority
Scoped, short-lived credentials bound the damage of a successful injection more reliably than trying to detect the injection itself. If an injected instruction persuades the model to make an unauthorised call, the credential still determines what the receiving system will accept.
Scope should match the operations and resources needed for the current task. A read task should not carry write authority. A workflow limited to one product environment should not receive authority over unrelated environments. Where a write is required, the credential should not silently include deletion or configuration authority unless those operations are part of the approved work.
Short lifetime adds a time boundary. A credential issued for a run should stop being useful after that run’s working window. This does not prevent a call made while the credential is valid, so it is not a substitute for tool restriction or approval. It limits how long successfully captured or redirected authority remains usable.
The cost is operational. Credentials must be issued, passed to the correct connection, refreshed when a legitimate task outlives them, and allowed to expire without breaking unrelated work. Scopes must be defined narrowly enough to matter. A nominally short-lived credential with broad authority can still permit substantial damage during its valid period; a nominally scoped credential that covers every destructive operation has not established a useful boundary.
This control is wrong only when it exists on paper but not at the point that authorises the action. Telling the model that it has read-only access does not constrain a credential that can write. The enforcement must happen in the service receiving the call or in a gateway that the call cannot bypass.
Pattern matching cannot establish safety
Detection by pattern matching fails for the same reason spam filtering does: the attacker adapts and the defender’s rules are public. A rule that blocks “ignore previous instructions” catches only payloads that continue using that phrase. The same intended redirection can be expressed with different words, split across fields, or presented as apparently benign operational guidance.
The attacker also controls the data being inspected. If a caption is rejected, the instruction can move to alt text, a filename, a tag, or another metadata field returned by the tool. If one phrase triggers a filter, the instruction can be paraphrased. The defender must recognise every useful form; the attacker needs one form that passes.
Pattern matching can still create an investigation signal, but it cannot justify granting a tool more authority. A match may identify text worth reviewing. No match does not establish that the result is safe. Treating a clean scan as permission to advertise destructive tools turns the detector’s blind spots into an authorisation path.
The OWASP guidance on risks in applications using language models and Simon Willison’s collected prompt-injection research and examples provide broader threat context. The durable conclusion for MCP tool results is narrower: controls should constrain what a model can do after reading hostile text, rather than assume every hostile meaning can be identified before the model reads it.
Pattern rules also create review work. Someone must maintain them, examine matches, and handle benign fields that resemble commands. That work may be justified for visibility, but it should not be mistaken for the boundary that protects irreversible operations.
Require approval for irreversible operations
Human approval on irreversible operations is the control that survives a novel phrasing, because it does not depend on recognising the attack. The model can misunderstand a caption, accept a completely new injection, and propose an action; the action still stops before execution.
Approval must cover the actual operation and its arguments. A prompt that says only “allow this tool?” does not tell the reviewer what will change. The reviewer needs to see the proposed tool, the target, and the arguments that determine the effect. Otherwise a hostile result can redirect the arguments while the approval surface makes the call appear routine.
The approval should occur after the arguments are fixed and immediately before the irreversible call. Approval of a general plan is not approval of every later call assembled from untrusted results. If arguments can change after review, the reviewed action and the executed action are not the same control decision.
The cost is latency and human attention. A workflow cannot run fully unattended when it reaches a protected operation. Repeated prompts can also train reviewers to approve without reading. That does not make approval unnecessary; it means the irreversible surface should be small enough that an approval remains unusual and meaningful.
Human approval is the wrong control for ordinary reads and reversible low-impact operations when it adds prompts without protecting a real boundary. It belongs where the consequence cannot be readily undone or where the action extends beyond what the user explicitly requested. Tool restriction should remove irrelevant operations first, leaving approval to guard the smaller set of powerful operations that a legitimate task may sometimes need.
Log arguments and results together
Log the tool arguments as well as the results, since the evidence of a successful injection is a call the user never asked for. A result-only log can show the hostile caption or metadata but omit the action it caused. It can also show the response from a destructive call without preserving which target or options the model supplied.
The useful record connects the user’s request, the tool selected, the arguments sent, and the result returned. The critical evidence is the divergence: the user asked for one operation, an untrusted field appeared, and the model called another tool or changed the arguments. Without the call arguments, an investigator may know that something happened but not what the model attempted.
Arguments are also necessary when the unexpected behaviour is subtle. The injected instruction may keep the same tool name while changing a target, mode, destination, or other field. A list of invoked tools would make that sequence look normal. The arguments reveal that the call no longer matched the user’s request.
Logging has a storage and handling cost because both arguments and results can contain user-authored content. The record should therefore be kept deliberately rather than treated as incidental debug output. The security requirement is completeness at the decision boundary: preserve enough of the request, call, arguments, and response to reconstruct why the operation was outside the user’s intent.
Logs do not prevent the first unauthorised call. Their job is to expose it, support investigation, and show whether tool restriction, credential scope, or approval failed to stop it. A detection system that records suspicious result text but discards the resulting calls preserves the possible lure while losing the evidence of success.
The control boundary to check next
A review should start with the advertised tools, then check the credentials behind those tools, the approval boundary for irreversible operations, and the call record that would prove what happened. Pattern matching can add a signal around that boundary, but it cannot replace any of those controls.
For each connection, verify that a hostile filename, caption, tag, description, or metadata value cannot introduce a capability that the task did not already require. Where a powerful tool must remain available, verify that its credential scope limits the affected resources and operations, its lifetime matches the work, and its final arguments are visible before an irreversible action is approved.
Finally, inspect the logs from the perspective of an investigator who did not observe the run. They should be able to distinguish the user’s request from retrieved content and compare that request with every tool call’s arguments and result. If the record cannot show that the model made a call the user never asked for, it cannot establish whether prompt injection through a tool result succeeded.
Sources
- current MCP specificationmodelcontextprotocol.io
- OWASP guidance on risks in applications using language modelsowasp.org
- Simon Willison's collected prompt-injection research and examplessimonwillison.net
See also
How to turn on cloudinary-embed-headers so every MCP tool result carries the rate-limit ceiling, remaining allowance, reset time and request ID.
Use the cloudinary-tools header to allowlist tools on a remote MCP connection: fewer definitions in context, better targeting, and server-side enforcement.
Build a query-led, validated metadata schema through Cloudinary’s Structured Metadata MCP server without overloading uploaders.
What Cloudinary's Structured Metadata MCP server does: typed fields, controlled values, conditional rules, stable external IDs, and search-expression queries.