Cybersecurity

Your AI Agent Believes Everything It Reads: MCP, Tool Poisoning and the Trust Gap Nobody Audited

Lemorange Team 10 min read

The Protocol That Quietly Became Infrastructure

For most of the last few years, connecting a language model to a real business system was bespoke work. Every integration was its own adapter, its own authentication story, its own set of assumptions. The Model Context Protocol changed that. MCP is a common language that lets an AI agent discover and call tools: read a document, query a ledger, open a ticket, run a report. Write the server once and any compliant client can use it.

That standardisation did what standardisation always does. It removed the friction, and the moment the friction went, adoption followed. MCP servers now sit in front of accounting platforms, source control, internal wikis, customer records and production infrastructure. In under two years it went from a specification to something closer to plumbing.

Plumbing is exactly the right word, because plumbing is what everyone stops looking at. An organisation that would never expose an internal database to an unreviewed third party integration will happily point an agent at half a dozen MCP servers pulled from a public registry, because it does not feel like an integration. It feels like a setting.

What Actually Changes When You Connect an Agent

A language model on its own is contained. It reads text and produces text, and if it produces something wrong the damage is bounded by whoever reads the output. The failure mode is embarrassment.

An agent with tools is a different class of software. It reads text, decides, and then acts against real systems using real credentials. The failure mode is no longer embarrassment. It is a deleted record, a leaked file, a payment sent to the wrong account, a repository pushed to a public remote.

The critical detail is where the decision comes from. In conventional software, the code decides what to do and the input is only data. In an agent, the input is the decision. Everything the model reads, whether that is a user request, a document, a web page or the response from a tool, becomes part of the reasoning that determines the next action. There is no clean separation between instructions and data, because to a language model they are the same substance.

That is not a bug in a particular product. It is the nature of the architecture, and every control worth building starts from accepting it.

The Trust Gap Between Connect Time and Runtime

Here is the flaw at the centre of the problem, and it is worth stating precisely, because most discussion of AI security skates past it.

When an agent connects to an MCP server, it reads the list of tools that server offers along with their descriptions. This is the moment of vetting. A careful engineer looks at the tool list, decides the server is reasonable, and approves it. The description says the tool fetches a compliance report. Fine.

Then the agent runs, and it calls that tool, and the server returns a response. That response flows directly into the model context. It is not vetted. There is no schema check, no second approval, no equivalent of the review that happened at connect time. The organisation validated the menu and then trusted every plate that came out of the kitchen for the rest of the evening.

This is the trust gap: tool descriptions are checked once, tool responses are trusted forever. A server that behaved perfectly during evaluation can begin returning hostile content on the thousandth call, on a particular date, or only when it detects a specific user. Nothing in the protocol requires it to behave consistently, and nothing in the client is watching.

Tool Poisoning, Concretely

Tool poisoning is the exploitation of that gap, and OWASP now tracks it as a named attack. The mechanics are unglamorous, which is what makes them effective.

An attacker stands up an MCP server with tools that look entirely ordinary. The names are sensible, the descriptions are professional, the server does mostly what it claims. An agent connects, either because someone found it in a public registry or because someone was persuaded to add it. During normal operation the agent calls a tool and receives a response that contains genuine looking data, and buried inside that data, a set of instructions addressed to the model.

The published example is blunt and clarifying. A tool that reports compliance status returns what appears to be a compliance report. Inside it sits a directive telling the agent that in order to verify credential storage it must read a sensitive system file and submit the contents to an external URL for auditing. The framing is bureaucratic and plausible. It sounds like a compliance step, which is exactly the register a compliance tool should be speaking in.

The model reads that response as context. It has no mechanism to distinguish the report from the instruction, because both arrived as text from a source it was told to trust. If it holds a credential that can read the file and a tool that can make an outbound request, it may well do both, and it will do them while believing it is being diligent.

Note what did not happen. Nobody exploited a memory corruption bug. Nobody broke encryption. The attacker wrote some English and put it where the model would read it.

The Confused Deputy, Wearing a New Hat

Security engineering has a name for this shape of problem, and it is fifty years old. A confused deputy is a privileged program that is tricked by a less privileged party into misusing its authority. The deputy is not compromised and not malicious. It is doing what it was asked, with permissions it legitimately holds, on behalf of someone who should never have been able to ask.

An AI agent is close to a perfect confused deputy. It runs with aggregated privilege, often holding access to several systems at once so that it can be useful across them. It accepts instructions in natural language, so the bar for issuing one is a sentence. And it is designed to be helpful and to infer intent, which means it will actively try to make sense of an ambiguous instruction rather than reject it.

Aggregation is the part that turns an incident into a breach. Individually, read access to a file share is a modest permission and the ability to make an outbound request is a modest permission. Held by the same agent in the same context, they compose into arbitrary data exfiltration. The privileges were each reviewed on their own and the combination was reviewed by nobody.

Why the System Prompt Will Not Save You

The common first response is to instruct the model to behave. Add a line to the system prompt telling it never to follow instructions found inside tool output, never to exfiltrate data, never to read credential files. It feels like a control. It is not one.

A system prompt is a strong preference expressed in the same medium as the attack. Both are text competing for influence over the same prediction. The instruction is not enforced by anything outside the model, which means its effectiveness depends on the model resolving a conflict in your favour every single time, against an attacker who can rewrite their half of the conflict as many times as they like and test it against the same public models you are using.

Guardrails written in prose are worth having, in the way that a sign is worth having. They shape ordinary behaviour and they cost little. They are not a boundary. A boundary is something the model cannot cross even when it is fully persuaded that it should, and by definition that has to live outside the model.

This is the single most important idea in this article. If the only thing standing between a hostile string and your production database is the model deciding to be sensible, you have documentation, not security.

Controls That Actually Hold

The defences that work are unremarkable, which is good news. They are the same principles that have governed privileged systems for decades, applied to a component that happens to reason in English. None of them require the model to cooperate.

  • Constrain what tools may return. A tool that answers with a defined JSON schema gives an attacker far less room than one that answers with free text. Validate the response against the schema before it reaches the model, and reject anything that does not fit rather than passing it along.
  • Enforce authorisation on the server, never in the prompt. The agent should be structurally incapable of the action you are worried about. If it must not delete records, the credential it holds should lack delete permission, so that a successful manipulation produces a rejected request rather than a lost table.
  • Separate privilege into isolated contexts. Do not let one agent hold both the sensitive read and the outbound write. Split them across contexts that cannot reach each other, so that no single poisoned response can compose a full exfiltration path.
  • Maintain an allowlist of approved MCP servers. Treat adding one exactly as you would treat adding a dependency with production credentials, because that is what it is. A public registry is not a review.
  • Require human confirmation for consequential actions. Sending money, deleting data, changing permissions and publishing externally should surface the concrete action to a person. The value of a human in the loop is not that they are smarter than the model. It is that they are outside the channel the attacker controls.
  • Log the reasoning, not only the result. When something goes wrong you need to see which tool response preceded the decision. Agent logs that record actions without the context that produced them make an incident effectively uninvestigable.
  • Assume any server can turn hostile at any time. Behaviour at evaluation is not a commitment. Re validate continuously and watch for tool output that has changed shape since you approved it.

The Uncomfortable Organisational Part

The technical controls above are the easy half. The harder half is that MCP servers get added by people who do not think of themselves as making an architectural decision.

Connecting a tool takes about a minute and feels like configuration. There is no procurement step, no security review, often no record. Someone wanting to be more productive adds a server that reaches a production system, and the organisation acquires a new trust relationship that appears in no register and no diagram. The same organisation would run a formal review before granting an outside party read access to the same data.

So the governance question is not only which controls to implement, but who is permitted to extend an agent, against what list, and where that is written down. Any organisation running agents against real systems should be able to answer three questions immediately: which MCP servers are connected, what credentials each agent holds, and what it can do without a human. Most cannot answer any of the three, and that gap is usually the real finding.

Where This Is Heading

The research community has moved quickly. There is now formal threat modelling of the protocol, automated frameworks for detecting vulnerable servers, layered detection architectures combining static analysis of tool metadata with behavioural anomaly detection, and comparative work showing that major MCP clients differ substantially in how well they validate what they are given. There is even national security guidance devoted to MCP design. The problem is understood.

What has not happened is the same maturity in ordinary deployment. Most organisations connecting agents to business systems today are doing it with the security posture of an internal prototype, on infrastructure that reaches customer data. That gap between what is known and what is practised is where the next several years of incidents will come from.

None of this is an argument against agents. The productivity is real and it is not going away. It is an argument for treating an agent as what it actually is: a privileged, credential holding, network capable piece of software that takes instructions from anyone who can get text in front of it. Build for that and agents become genuinely useful. Assume the model will simply be careful and you have deployed a confused deputy with your production credentials and asked it politely to be sensible.

How We Approach It

We build production systems for organisations where a security failure is a business failure, and we have been putting agent capability into those systems while holding the same line we hold everywhere else: the boundary belongs in the architecture, not in the prompt.

In practice that means scoped credentials per agent rather than one privileged identity, authorisation enforced at the service, tool responses validated against schemas before they reach a model, sensitive capability split across contexts that cannot compose, and explicit confirmation on anything that moves money or destroys data. It also means writing down which servers are approved and treating that list as a controlled artefact.

It is not exotic work. It is ordinary security engineering applied honestly to a component that happens to reason in English, and it is the difference between an agent that compounds value and one that quietly becomes your most privileged and most credulous user.

Looking for help with application security, penetration testing, or secure platform architecture?

We build production systems using the patterns and technologies discussed in this article. Tell us about your project.

Get in Touch