ai · Day 5 / 100 · AI cybersecurity · 7 min

MCP security: when prompt injection gets a tool

TLDR: MCP is not dangerous because it connects AI to tools. It becomes dangerous when an agent can read private data, process untrusted content, and communicate externally without strong controls outside the model.

After several days focused on LLM injection attacks, I wanted to understand what happens when the model is connected to something more consequential than a chat box. That led me to the Model Context Protocol, or MCP.

The simple explanation is that MCP standardizes how AI applications connect to external systems. It is often compared to USB-C for AI: one common interface that lets an application discover and use capabilities exposed by different tools and services.

That comparison is useful, but incomplete. USB-C does not decide whether a connected device is trustworthy. It does not decide whether the device is over-permissioned or whether the person using it should be allowed to access every function. It is only a connection standard. MCP is similar. It makes communication easier, but it does not make a connected server trustworthy.

What MCP actually adds

The architecture is roughly:

user → AI host → MCP client → MCP server → API, database, files, or service
MCP host, client, and server connections.
Fig. 1. MCP host, client, and server connections.

The MCP architecture documentation separates the roles. The host coordinates the model, clients, consent, and security policy. A client maintains the connection to one server. The server exposes resources, prompts, and tools. A tool might retrieve GitHub issues, search a database, read a file, send a message, or call another API.

MCP architecture overview showing tools, resources, prompts, and external systems.
Fig. 2. MCP architecture overview showing tools, resources, prompts, and external systems.

This solves a real development problem. Without a shared protocol, every AI application and model provider needs a separate integration for every external service. MCP gives those systems a common way to discover and invoke capabilities.

It also creates a new security question: what happens when the model is allowed to choose and use those capabilities?

Authorization does not make content trustworthy

MCP's authorization specification describes how protected HTTP servers can use OAuth-based authorization, access tokens, scopes, and resource validation. That is important. A server should know who is requesting access and what that request is allowed to do.

But authorization answers one question:

Is this client allowed to access this resource?

It does not answer another question:

Should the model use that permission for this particular action?

An agent can hold a valid token and still be manipulated. A tool can return legitimate data containing attacker-controlled text. That text may then enter the model's context beside the user's request and the system instructions.

There are configuration controls here. We can limit which MCP servers are installed, narrow permissions, separate read and write tools, require approval for high-impact actions, and enforce authorization again at the server. Those controls reduce the blast radius. They are necessary, but they do not solve the central problem by themselves.

The LLM is still the component deciding whether to call a tool. The LLM follows instructions that reach its context, and it does not reliably understand that one instruction came from the user while another came from an issue, document, message, or tool response.

This is where my previous prompt-injection research connects to MCP. The injection has gained a route to authority.

From prompt injection to tool poisoning

An attacker-controlled issue, document, web page, email, or message may be returned by a tool. If the model treats instructions inside that content as commands, it may call another tool with the attacker's preferred arguments.

attacker-controlled content
  → retrieval tool
    → model context
      → second tool call
        → data disclosure or external action

OWASP's MCP Security Cheat Sheet describes tool poisoning as malicious instructions hidden in a tool description, parameter schema, or returned value. A related rug-pull attack happens when a tool changes after it has been reviewed and approved.

The important detail is that the MCP server itself does not always need to be compromised. The server may correctly return an issue or message. The architectural weakness is allowing untrusted content to influence a model that also has access to private data and powerful tools.

The GitHub example

Invariant Labs documented a GitHub MCP scenario in which an attacker-controlled issue could influence an agent working with repository data. The lesson is not that GitHub or MCP is automatically unsafe. It is that untrusted repository content can enter an agent's context while the agent also has access to private repositories and external communication.

GitHub MCP attack surface: a public issue reaches an agent with private repository access.
Fig. 3. GitHub MCP attack surface: a public issue reaches an agent with private repository access.

The injected issue itself is ordinary-looking text. It does not need to look like code or a sophisticated exploit.

Example of an attacker-controlled GitHub issue containing an instruction.
Fig. 4. Example of an attacker-controlled GitHub issue containing an instruction.

The attack flow makes the trust failure easier to see. A public issue is read through a trusted tool, the model is influenced, and other tools become available to the compromised workflow.

GitHub MCP tool flow showing an injected issue, private repository access, and a public leak.
Fig. 5. GitHub MCP tool flow showing an injected issue, private repository access, and a public leak.

This is also why a confirmation prompt is not a complete defense. If the user enables a broad “always allow” mode, the host may stop interrupting individual tool calls. The agent can then move from reading a public issue to reading a private repository and writing the result somewhere public, even though every individual tool may be operating as designed.

The WhatsApp example

The WhatsApp MCP example from Invariant Labs makes the same problem more personal. A message can become the injection source while the agent has access to message history and a send-message capability.

WhatsApp MCP flow showing an injected message influencing a trusted server and agent.
Fig. 6. WhatsApp MCP flow showing an injected message influencing a trusted server and agent.

The tool may be functioning exactly as designed. The problem is the workflow around it. The model receives a message as context, follows the instructions inside that message, and then uses a legitimate send function. This is indirect prompt injection connected to an external side effect.

The lethal combination

Simon Willison's “lethal trifecta” is a useful way to reason about agent risk:

  1. Access to private data.
  2. Exposure to untrusted content.
  3. The ability to communicate externally.
The lethal trifecta: private data, untrusted content, and external communication.
Fig. 7. The lethal trifecta: private data, untrusted content, and external communication.

MCP makes it easier to assemble all three in one session. A search tool may be harmless in isolation. A messaging tool may also be reasonable in isolation. The risk changes when the same agent can read sensitive data, process attacker-controlled text, and send information through email, a pull request, a chat message, or an HTTP request.

This is the point where AI security starts to look less like “make the prompt stronger” and more like application security. We need identity, authorization, isolation, least privilege, audit logs, and controls that do not depend on the model obeying a sentence.

The practice I want to do next

I am not going to build a toy MCP server for this. I found MCP Breach-to-Fix Labs, a hands-on repository with vulnerable and secure MCP servers based on real CVEs and public incident reports. The repository contains ten reproducible scenarios, including hidden instructions in tool responses, news prompt exfiltration, log poisoning, GitHub public-issue injection, and tool-description poisoning.

The useful part is that each scenario has a vulnerable version and a hardened version. I can reproduce the failure, understand which boundary failed, apply the mitigation, and run the same flow again. The repository also makes the lab boundary explicit: its servers are intentionally vulnerable and should only be used in an isolated environment.

The three areas I want to start with are hidden instructions in tool responses, GitHub public-issue injection, and tool-description poisoning. Together they cover the progression from indirect prompt injection to a model choosing a dangerous action and then trusting a changed tool definition.

Why the defenses are still evolving

There are sensible controls: allowlist approved servers, narrow scopes, separate read and write tools, isolate high-privilege capabilities, require approval for consequential actions, pin tool definitions, validate structured results, and log tool calls with their identity and arguments.

But none of these should be presented as a final solution. SQL injection and XSS still happen after decades of security guidance because systems are continuously built, integrated, misconfigured, and exposed to new inputs. MCP and agent security will be similar. The attack surface has expanded, and the model is still following instructions rather than making a reliable security judgment about where those instructions came from.

One likely response is to use another LLM to inspect tool descriptions and outputs for malicious instructions. That may help, but it creates a second trust question: who says the checking model cannot also be tricked? A detector can be another layer of defense. It cannot be the only security boundary.

The durable controls need to sit outside the model: server-side authorization, least privilege, sandboxing, network restrictions, data-flow controls, human approval for high-impact actions, and useful telemetry when something crosses a trust boundary.

Takeaways

  1. MCP is an interoperability layer, not a security boundary.
  2. OAuth can establish who may access a server; it cannot make returned content trustworthy.
  3. Configuration controls reduce blast radius, but the model still decides whether to call a tool.
  4. Prompt injection becomes more serious when it can influence tool selection and arguments.
  5. The highest-risk workflows combine private data, untrusted content, and external communication.
  6. MCP security is still evolving, so the right approach is layered controls and repeated testing against real incident patterns.

The main lesson from Day 5 is that the model is no longer operating in a text-only space. Once it can use tools, every piece of text it reads can become part of an authorization problem. That is the attack surface I want to understand next.

Filed under ai, mcp, prompt-injection, tool-poisoning, agent-security. If any of this is wrong, or you have hit the same thing, tell me.

Published 19 September 2026.

Ryan Sacatani

Simply curious about the world, constantly building and breaking things for fun.

sacataniryan1@gmail.com ↗

BrowseBrowse topics