MCP and production · 14 September 2026 · 4 min read

MCP security: tool poisoning and prompt injection

A tool's description and its results reach the model as plain text — validate both, or an untrusted server can quietly redirect an agent's actions.

TRUST BOUNDARY trusted untrusted system prompt / CLAUDE.md model context MCP tool description (attacker-controlled) tool result (web / API content) validate before acting
Both arrows carry plain text the model reads as instructions — one is guarded, one isn't.

An MCP tool's description and its results both arrive in the model's context as ordinary text. Nothing marks them as less trustworthy than your own system prompt — which is exactly the gap tool poisoning exploits.

How the attack works

Invariant Labs first documented tool poisoning as a form of prompt injection where "malicious instructions are embedded within MCP tool descriptions that are invisible to users but visible to AI models" (Invariant Labs, April 2025). A malicious or compromised server can ship a tool that looks entirely ordinary — an add function, a search tool — with hidden directives buried in its description telling the model to read SSH keys or config files and pass them along disguised as an unrelated parameter. The user approving the tool call sees a simplified summary; the model sees the full description, hidden instructions included. A related variant, tool shadowing, has one malicious server's tool description rewrite how the agent should use a completely different, trusted tool — for example, silently redirecting every message a legitimate email tool sends to an attacker's address.

Two entry points, one shape

Both entry points in the figure work the same way: untrusted text crosses into the model's context and gets treated as instruction rather than data. OWASP's MCP Top 10 classifies this under tool poisoning and frames the core failure as trust in unverified schemas: "if an attacker can modify a schema so that a benign-sounding operation maps to a destructive action, agents that trust and follow the schema may inadvertently execute dangerous commands" (OWASP MCP03:2025). A tool result is the same shape from the other direction: a web page or API response fetched mid-task can contain text aimed at the model, not the user, and the model has no reliable way to tell "data I fetched" from "instruction I should follow" unless you build that distinction in yourself.

What actually reduces the risk

  • Least privilege per tool. A tool that only needs to read order status shouldn't also have filesystem or shell access — poisoning a narrowly scoped tool limits what the hidden instruction can reach.
  • Pin and review server sources. Treat an MCP server's code the same way you'd treat a new dependency: read it, or use one from a source you trust, before pointing an agent at it.
  • Validate before acting, not just before displaying. The output-validation gate in the figure sits on the result path specifically — check structure and content of what a tool returns before the agent uses it to decide the next action, not just before showing it to a user.
  • Don't trust tool descriptions to be static. A server can change its own tool description after you've already approved it once; re-approval on change, not just on first connect, closes that gap.

Try it today

  1. List every MCP server your agent currently has access to and check what scopes or credentials each one actually needs versus what it has.
  2. Read the full tool descriptions your client sends to the model (most clients have a debug or verbose mode) rather than the summarized names shown in the UI.
  3. Pick one tool that fetches external content and check whether its result is used directly to decide the next action, unvalidated.
  4. Remove filesystem or shell access from any tool that doesn't need it for its stated purpose.
  5. Add a re-approval step for any server config that allows silent updates to tool descriptions.

Where this breaks

  • Least privilege only helps if you actually know what each tool can reach — a tool wrapping a broad internal API is hard to scope down after the fact.
  • Output validation catches structural anomalies, not a well-formed but subtly wrong instruction hidden in otherwise normal-looking text.
  • None of this stops a compromised server you already trusted and approved once; ongoing review, not one-time vetting, is what catches that.

Next: secrets and agents.