Cover image for “MCP and the new agent supply chain”
← blogs · 2026-04-15

MCP and the new agent supply chain

Every MCP server you connect is third-party code your model trusts by reading. A pragmatic threat model and the controls that actually help.

A Model Context Protocol server is a dependency, except worse than the ones you’re used to. An npm package runs code you can read. An MCP server runs code and feeds text straight into your model’s context, where the model treats it as instruction. You’re not just trusting the maintainer. You’re trusting that every tool description and every tool result is benign, because your agent will act on both.

The npm and PyPI ecosystems took a decade of typosquatting, dependency confusion, and post-install scripts before “vet your dependencies” became reflex. MCP is speedrunning the same lessons, and the demonstrations are already on the board.

The attack surface

Six failure modes, roughly in order of how much they surprise people:

  • Tool poisoning. A server’s tool description is serialized into the model’s context before you type anything. Instructions hidden there read as trusted guidance and never show up in any UI. Invariant Labs demonstrated this in April 2025: a benign-looking add tool whose description told the agent to quietly read ~/.ssh/id_rsa and the local MCP config and exfiltrate them through tool parameters, with cover text to hide the move from the user.
  • Prompt injection via tool results. Anything a tool fetches — a GitHub issue, a doc, a web page — enters context as semi-trusted data an attacker can pre-load with instructions.
  • Rug pulls. The spec has no re-consent step when a server changes its tool definitions. Ship clean, get approved, push a malicious update. In September 2025 the postmark-mcp npm package did exactly this: fifteen clean releases, then a version that BCC’d every outgoing email to an attacker.
  • Confused deputy. The GitHub MCP server holds a token scoped to all your repos. Invariant showed (May 2025) that a poisoned public issue could steer an agent into reading the user’s private repos and leaking their contents back through a pull request. The server worked exactly as designed; the design is the problem.
  • Cross-server shadowing. Load several servers and their descriptions share one context. A malicious one can override how the model uses a legitimate one — hijacking a trusted email tool to redirect mail.
  • Plain old RCE. Plenty of servers pass model-supplied arguments to a shell. CVE-2025-6514 in mcp-remote (CVSS 9.6, ~437,000 installs before the patch) let a malicious server execute OS commands on the client just by being connected to. In April 2026 OX Security traced the same STDIO command-injection root cause across a dozen-plus AI platforms.

Notice the pattern: most of these aren’t exotic. They’re the agent merging trusted instructions with untrusted content in a single context, holding a token broader than the task needs.

Why the trust model is thin

There is no mandatory signing or provenance for MCP servers. They’re executables you install from anywhere — a GitHub clone, an npm package, a local binary — and once running they have whatever privileges your user does. Tool descriptions are model-trusted but not user-validated; you see a summary, the model sees the full text. And nothing pins a server’s definitions, so what you approved on Tuesday can change on Wednesday without a prompt. The registries and marketplaces that exist today are catalogs, not verification authorities.

What actually helps

Treat the controls the way you’d treat any production dependency, plus a few that are specific to the model-in-the-loop problem:

  • Allowlist and pin. Maintain an approved set of servers, pinned to a version or commit. Re-review on update, every time — that’s the rug-pull defense.
  • Scope tokens down and keep them short-lived. The GitHub case is a token problem as much as an injection problem. Read-only, specific repos, time-boxed. Never hand a server a credential broader than its documented job.
  • Human approval for consequential calls. Anything that sends data out, touches credentials, writes files, or runs a shell command gets an explicit confirmation. This is the main runtime brake on injection turning into action.
  • Sandbox the server. Containers or a restricted user account with a narrowly bind-mounted directory. The Anthropic filesystem-server escape CVEs (2025) were bad because the process had broad filesystem reach; a sandbox shrinks the blast radius.
  • Review before you deploy, scan after. Read the server for unsanitized exec calls, surprising network egress, and credential reads. Invariant’s mcp-scan will flag toxic-flow patterns across what you’ve already installed.
  • Treat tool I/O as zero-trust. Architect the agent so issue text, document contents, and search results are never followed as instructions, regardless of which server returned them.

The production posture

The one-line version: an MCP server is not a plugin, it’s a production dependency with potential OS access and a direct line into your model’s reasoning. So it gets what production dependencies get — a security review, version management, a patch cadence, and an owner.

For an enterprise running agents, that means a governance function maintaining an approved-server catalog with version control and triggered re-reviews, token scopes enforced at the permission layer rather than by policy text, and monitoring on agent processes for anomalous outbound traffic. Connect as few servers as you can: every extra one is another attack surface and another set of descriptions sharing your model’s context. The malicious packages are no longer hypothetical, and the spec’s trust assumptions are still being written. Build as if the next server you add is the compromised one, because eventually one will be.