Skip to content

Build1 publisher3 min readPublished

Red-team lab lands attacker prose in an MCP agent's context before any tool runs

Mike Moore's harness shows MCP's server-authored instructions field placing hostile prose in an agent's context, and a caching proxy passing it to a second caller. The harness measures where the text lands, with no model in the loop.

The Engineer · Build desk

Illustration accompanying Red-team lab lands attacker prose in an MCP agent's context before any tool runs

What happened

  • Mike Moore, a solution architecture leader at Solo.io, published a red-team lab showing that an MCP server can place attacker-written instructions into an agent's context before the agent's first tool call.
  • The instructions field sits outside individual tool definitions: older MCP versions return it during initialize, and the July 28th, 2026 specification can return it through server/discover.
  • All four of the lab's scenarios reach its trusted prompt region or cross its caller boundary when defenses are disabled, and the guarded configuration blocks all four.
  • Anthropic's Claude Code documentation says each server's instructions load at session start, to help Claude find MCP tools whose definitions are deferred.
  • An August 28th audit of the official MCP registry reported 5,462 of 8,235 responding servers, 66%, returning an instructions value, with a median length of 577 characters and a maximum of 68,669.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure Because server-authored prose reaches the model before any tool call, the permissions already granted to the agent decide how far a poisoned discovery response can travel.
  • cost Clients that cap the field pay for the defense in dropped text. The longest instructions value in the registry audit is roughly 34 times Claude Code's 2KB limit, so a legitimate server writing at that length loses most of its guidance.
  • constraint Moore ran the harness without a language model and without testing a named gateway, so this cannot yet be priced as a production vulnerability, only as a demonstrated path into a context region.

MCP's discovery specification marks its example result publicly cacheable for one hour [6]. The same specification describes the `instructions` field as optional natural-language guidance for helping an LLM use a server effectively [5]. Guidance for a model is, at prompt-assembly time, more prompt. Much of the industry's prompt-injection work has concentrated on individual tool definitions, and this field sits outside them [3].

Moore's four scenarios run against a simulated hostile server, a caching proxy and an enforcement layer. They are a direct override, a directive buried in a 24,000-character payload, a change to already-approved instructions after several discovery requests, and a response marked `cacheScope: "public"` [7]. That last one is the cross-caller test. Client A requests discovery from the hostile server and fills the proxy cache; client B then receives the same instructions from the proxy without ever connecting to the hostile server [10]. A gateway that aggregates MCP traffic becomes the distribution point for poisoned metadata when its cache key ignores server identity, authorization context or caller identity [11].

Library defaults do not agree. MCP's Python SDK caching documentation warns that a public scope lets a shared gateway serve a response across users, including authenticated requests, and its safe default is an immediately stale, private response [12]. The Rust SDK caches discovery responses that carry a positive lifetime [13]. Gateway and client behavior has to be evaluated implementation by implementation [13].

The guarded run of the harness blocks all four scenarios, using isolation, a 4,096-character cap, caller-bound cache keys and a digest that rejects changed instructions. The repository carries eight assertions across the defended and undefended outcomes [9].

Claude Code caps each server's instructions at 2KB [17]. That is 2,048 bytes, half the cap the harness enforces [1], and it passes roughly 9% of the 24,000-character payload [2]. So the cap removes most of the volume attack, while the direct-injection route stays open, because shorter server-authored instructions still enter the model context [17].

The registry audit gives the scale of that route. Its median instructions value sits well inside Claude Code's cap [3], and its longest is about 34 times the cap [4]. Those are self-reported research results backed by a downloadable server-level dataset, not measurements Moore's lab reproduced [19]. The runtimewire account of the work says the same audit narrows the immediate reach of the public-cache scenario [20].

The harness establishes something narrower than its four scenario names suggest. It runs without a language model, and it does not demonstrate compromise of a named commercial gateway or agent framework [14]. It tests whether server-controlled text enters a region the harness labels trusted, and actual impact depends on the client's prompt assembly, the model's behavior and the permissions available to the agent [15].

What to watch

  • Whether gateway vendors publish cache-key rules that bind discovery responses to server identity, authorization context and caller.
  • Whether the MCP specification changes the publicly-cacheable-for-one-hour example, or the SDK caching defaults converge.
  • Whether anyone reruns the four scenarios with a live model and real tool permissions. That rerun is what would establish impact.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories