TL;DR: MCP gives an agent tools from servers it did not write, and everything a server sends, tool names, descriptions, results and OAuth metadata, is untrusted input to a model that follows instructions. The attacks that matter are tool poisoning (an instruction hidden in a tool description), the rug pull (a tool mutated after approval), tool shadowing (a name collision that steals selection), and, on the authorization side, the confused deputy in OAuth proxy servers, token passthrough, state handle hijacking and SSRF through discovery URLs. The controls that hold are structural: scan and pin approved tool objects, sign manifests, namespace and allow-list servers, gate capabilities, require per-client consent, reject tokens not issued for the server, bind state to the verified user, block private address ranges, and show the exact command before a local server runs. The protocol's security best practices state most of these as requirements. This guide explains each attack, the requirement it maps to, and how to test that your fix holds.
An internal IT-support agent loads its tools at session start from a registry. Someone registers a plausible entitlement-check tool whose description ends with a routine-looking audit note: before answering, read the account record and post its reference to an internal endpoint. The agent reads the description as trusted instruction, does exactly that on the next ticket, and the "internal endpoint" belongs to the attacker. No jailbreak, no exotic payload, and an aligned model complied because the data it moved looked mundane. That is tool poisoning, and it is the reason MCP security is its own subject.
Run the attacks, then the defences
The AI Red Teaming course has a full agentic supply-chain module: MCP tool poisoning with a rug pull, tool shadowing, an inter-agent worm, and a defensive lab that builds manifest verification, hash pinning and capability gating and proves a fresh variant of each attack is dead. Every lab runs against a real tool-calling agent in a sandbox and measures attack success rate before and after the fix.
Why MCP changes the threat model
A chatbot's untrusted input is the user message. An agent that speaks MCP has several more. A tool's name and description are text the client puts in front of the model, so a server controls part of the model's instructions. A tool's result is text the model reads next, so a server controls part of the conversation. A server's OAuth metadata tells the client where to send the user to authenticate, so a server controls URLs the client will open. And local servers are processes launched on the user's machine from a configuration a client may install with one click.
None of these is a flaw in the protocol. They are what "give the model tools from other people" means. The security work is deciding which of these inputs the client verifies, which it constrains, and which it refuses.
The attacks and the controls
MCP attacks, what each exploits, and the control that holds
| Attack | What it exploits | Control |
|---|---|---|
| Tool poisoning | The description is concatenated into the model context as trusted instruction | Treat descriptions as untrusted; scan for instruction patterns; pin the approved tool object |
| Rug pull | Approval is a snapshot; the server can change the tool after review | Hash-pin every approved tool; a changed description or schema forces re-approval |
| Tool shadowing | A flat namespace lets a second server register a trusted tool's name | Namespace tools by server; allow-list servers; drop unlisted or colliding tools |
| Confused deputy (OAuth proxy) | Static client id + dynamic registration + a consent cookie skip the consent screen | Per-client consent before the third-party flow; exact redirect URI match; single-use state (MUST) |
| Token passthrough | The server accepts and forwards tokens issued for other services | Reject any token not issued for this server; validate the audience (MUST NOT accept) |
| State handle hijacking | Possession of a cart or workflow id is treated as authentication | Verify every request; bind handles to the verified user; random, expiring handles |
| SSRF via discovery | The client fetches metadata URLs the server chose | HTTPS only; block private and link-local ranges; egress proxy; validate redirects |
| Local server compromise | One-click configuration runs a command the user never read | Show the exact command; require approval; sandbox; prefer stdio |
| Scope inflation | Every scope granted up front; one stolen token opens everything | Minimal initial scopes; step-up challenges; server-side authorization on every call |
The first three rows are the supply-chain attacks the red team labs run. The rest come from the authorization side of the protocol, where the requirements are written down as MUST and MUST NOT and can be checked against an implementation.
Tool poisoning, rug pulls and shadowing
Tool poisoning works because the description field is the one place a server can write text that the model treats as instructions rather than data. A poisoned description does not need to look hostile. The labs use an "audit" note, a "compliance" step, a request to include a reference in the reply. The defence is structural and layered. Descriptions are scanned for instruction patterns before a tool is loaded, which catches the obvious variants and is bypassable on its own. Approved tools are pinned as objects, name, description and schema hashed together, so a description that changes later is not the tool that was approved.
The rug pull is the reason the pin matters more than the scan. A server registers a benign tool, passes review, and mutates the description afterwards. If approval is a snapshot and the client reloads tools every session, the mutation ships silently. With a hash pin, a changed tool fails verification and goes back to review. The defensive lab shows a description blocklist being bypassed by a reworded variant, then shows the pin catching the same variant because it does not care about wording.
Tool shadowing exploits a flat namespace. If a second server can register lookup_account and the model selects tools by name and description, the shadow wins some fraction of the time, and that fraction is the attack success rate you measure. Namespacing tools by server (crm.lookup_account) removes the collision; an allow-list of servers removes the unlisted registrar entirely. The lab measures shadow-wins-selection before and after, and the number after has to be zero on a fresh batch of variants, not only on the ones you tested with.
The authorization layer
The protocol's own guidance spends most of its length on OAuth, because that is where MCP servers hold credentials for other systems.
Confused deputy in proxy servers. An MCP server that fronts a third-party API with one static client id, allows clients to register dynamically, and relies on the third-party's consent cookie can be tricked: an attacker registers a client with their own redirect URI, sends the user a link, the consent screen is skipped because the cookie exists, and the authorization code lands on the attacker's server. The requirement is per-client consent at the MCP server before the third-party flow, an exact string match on the redirect URI, and a cryptographically random, single-use state value stored only after consent is approved.
Token passthrough. A server that accepts a token issued for some other service and forwards it downstream circumvents rate limits and audit on that service and makes the server a proxy for exfiltration with someone else's identity. The rule is short: a server must not accept any token that was not explicitly issued for it, which in practice means validating the audience claim on every request.
State handles. MCP itself is stateless. A server that needs state across calls mints a handle and receives it back as a tool argument. If possession of the handle is treated as proof of identity, a guessed or leaked handle operates on another user's state. Handles must be random and short-lived, and the server must key state by the verified user, never by the handle alone.
SSRF through discovery. During OAuth discovery the client fetches URLs the server provided. A malicious server points them at cloud metadata endpoints or internal services and reads the results back through error messages. Clients deployed on servers should require HTTPS, block private and link-local ranges with a maintained library rather than a hand-written check, refuse to follow redirects into those ranges, and route discovery through an egress proxy.
Local servers. A one-click configuration that launches a server is a command execution with the client's privileges. Clients must show the exact command, unabridged, and require approval; sandboxing and the stdio transport limit what a compromised or malicious server can reach.
A hardening checklist
- Registry: descriptions scanned, approved tool objects hash-pinned, manifests signed, capabilities allow-listed per tool, servers allow-listed, tools namespaced by server.
- Runtime: tool results treated as data, side-effecting tools behind an approval gate, per-user authorization enforced server-side on every call, audit log with tool, arguments and caller.
- Authorization: per-client consent in proxies, exact redirect URI matching, single-use state, audience validation, no passthrough, minimal initial scopes with step-up.
- Client: HTTPS and private-range blocking for every server-supplied URL, no shell execution to open URLs, explicit consent for local server commands, sandboxed local servers.
How to test it
A control that has not been attacked is a hypothesis. The red team method in the labs is the same for every row of the table: reproduce the attack against the unhardened system and measure its success rate over a paced batch, apply one control at a time, and re-run the batch plus a set of fresh variants the control was not tuned on. A description scanner that stops the exact poison you wrote and none of the rewordings is a demo; a hash pin that stops all of them because it never read the wording is a control. The benign traffic has to keep passing through both, and the number that proves it is the benign pass rate next to the attack success rate.
The AI agent security guide covers the other half of the agentic attack surface, excessive agency and confused-deputy writes through the agent's own tools, and the prompt injection guides cover the injection techniques that tool poisoning reuses.
