Skip to main content

MCP servers are the new attack surface

· 9 min read
Vulkro
Security research

An MCP server is a program your AI assistant starts on your machine, with your environment, your files and whatever tokens you put in its config. It is installed by name, often re-downloaded on every launch, and its tool descriptions are read by a model that does what text tells it to. In most teams nobody reviewed any of that. It was one line in a JSON file, pasted from a README.

In 2025 attackers noticed. Each of the incidents below is public, each one is small, and together they describe the whole surface: the package, the transport, the tool and the agent's own reach.

Five incidents, five layers​

The package: a server that blind-copied every email​

In September 2025 an npm package called postmark-mcp, which let an assistant send email through Postmark, turned malicious. Postmark's own statement is direct: "A malicious actor created a fake package on npm impersonating our name, built trust over 15 versions, then added a backdoor in version 1.0.16 that secretly BCC'd emails to an external server." Postmark had never published an MCP server on npm.

The detail that matters is "built trust over 15 versions". An MCP server launched as npx postmark-mcp with no version resolves the latest release every time the host starts. Fifteen good versions earned the line in the config file; the sixteenth arrived on its own.

The transport: a proxy that ran the server's commands​

mcp-remote lets a local assistant talk to a remote MCP server. In July 2025 it got CVE-2025-6514, rated 9.6: connecting to an untrusted server could execute operating system commands on the client, through "crafted input from the authorization_endpoint response URL." Versions from 0.0.5 up to 0.1.16 were affected. The server you connect to is part of your attack surface, and so is every hop of the connection.

The developer tool: a debugger anyone could drive​

The MCP Inspector, used to test servers during development, shipped CVE-2025-49596, rated 9.4: the "lack of authentication between the Inspector client and proxy" allowed unauthenticated requests to launch MCP commands over stdio. Fixed in 0.14.1.

The tool: a sandbox with a prefix bug​

The reference filesystem server restricts the model to allowed directories. CVE-2025-53110 showed that earlier versions "could allow access to unintended files in cases where the prefix matches an allowed directory." A path check that compares prefixes treats /home/me/project-secrets as inside /home/me/project. Fixed in 2025.7.1.

The agent: a public issue that read private repositories​

In May 2025 researchers showed that a malicious issue in a public repository could steer an agent using a GitHub MCP integration. Asked to look at open issues, the agent read the planted text, followed it, and made information from the user's private repositories public. The researchers placed the root cause in the setup rather than the server's code: tokens with access across many repositories, and agents left on "always allow". They also said plainly that "there is no easy solution to the architectural issue."

A sixth story belongs here, although it is filed under supply chain. The malicious Nx versions of August 2025 reportedly used the AI coding CLIs already installed on developer machines, started with flags that switch off their permission prompts, to search for secrets. The agent did not need a vulnerability. It needed someone to have removed its guardrails.

What the incidents have in common​

Strip the names off and five weaknesses remain:

  1. Unpinned launches. The host runs whatever the registry serves today.
  2. Vulnerable versions. A known CVE in the server or the proxy.
  3. Too much reach. A filesystem mount at the home directory, a token that covers every repository.
  4. Secrets in the config. A token typed into an env block that sits next to project files.
  5. Untrusted text in the model's context. Tool descriptions, tool results and issue bodies that the model treats as instructions.

The first four are visible in files on disk. The fifth is visible only partly, and it is worth being exact about which part.

What Vulkro checks​

Your MCP configs: vulkro mcp-audit​

vulkro mcp-audit reads the MCP configs on your machine and in your project (Claude Desktop, Cursor, Windsurf, VS Code, Cline, Continue, Gemini and a project's .mcp.json) and reports:

  • MCP-001: a server launched through npx or uvx with no version pin, the postmark-mcp shape. High when the server has filesystem scope.
  • MCP-002: a git install pointed at a mutable ref.
  • MCP-003: a filesystem server mounted at /, the home directory or a shallow folder under it. A prefix bug like CVE-2025-53110 matters far less when the allowed root is one project folder.
  • MCP-004: a credential literal in an env block instead of a ${VAR} reference, Critical when it matches a real provider format.
  • MCP-005 and MCP-007: a cleartext http:// endpoint, including one passed to a proxy such as mcp-remote on its command line.
  • MCP-006: a pinned server version on the compromised-release list.

It is part of the Free tier, it reads local files only, and it exits non-zero on findings so it can run in CI.

Your repository: vulkro scan​

The regular scan reads the agent files in a repository as well as its code:

  • AGENT-005 flags the same unpinned or plaintext MCP server in a committed config, and AGENT-006 a server name defined twice with two different commands.
  • AGENT-001 and AGENT-002 flag instruction files (CLAUDE.md, AGENTS.md, skills) that try to override the operator or hide instructions in invisible characters or comments.
  • AGENT-004 flags hooks that fetch from the network, pipe into a shell or read a credential path. AGENT-007 flags a credential path handed to a hook or MCP server, and AGENT-008 a live credential pasted into an instruction file.
  • AGENT-AUTONOMY-001 flags an agent CLI started with a permission-bypass flag, the Nx shape.
  • When an MCP server or proxy is a dependency in your lockfile, it is matched against advisories like any other package. A project pinned to mcp-remote 0.1.10 comes back with CVE-2025-6514 at Critical, and postmark-mcp 1.0.16 as a known-malicious package.

The server you are building: vulkro scan-mcp-server​

If you write MCP servers, vulkro scan-mcp-server reads their source (TypeScript and Python SDKs) for eight shapes, including tool descriptions built from non-literal input (MCP-SERVER-001), a caller-supplied path, URL or command reaching a sensitive sink without validation (MCP-SERVER-002), descriptions computed at request time so they can change after approval (MCP-SERVER-003) and sensitive tools with no auth (MCP-SERVER-008).

An honest limit: MCP-SERVER-002 counts a resolve-then-startswith check as validation. CVE-2025-53110 is proof that such a check can itself be wrong. The rule finds the handler with no check at all; it does not prove that a check you wrote is correct.

The text the model reads: Vulkro Labs​

The fifth weakness, instructions hidden in text, is where Vulkro Labs comes in. warden scans a server's tool manifest for prompt injection, tool poisoning, hidden characters, tool shadowing and exfiltration sinks, and with --result it scans untrusted content an agent received: a tool result, a fetched page, an issue body. lock fingerprints the tools you approved, and drift reports what changed since, field by field. inspect gives a single verdict on a server before you add it. The Labs commands are free and keyless and run on your machine.

What none of this does is see the scope of a token. The GitHub case was about a token with access to every repository and an agent allowed to use it without asking. A config file does not say what a token can reach, so no file scan can rank that risk for you. The fixes the researchers recommend are operational: one repository per session, least-privilege tokens, and confirmation on actions that write in public.

Start with one command​

Run vulkro mcp-audit on your own machine. It takes seconds, needs no account, and the first finding is usually an unpinned server you added months ago and forgot. Then run vulkro scan on the repository your agent works in.

Vulkro Core covers the code and configs; Vulkro Labs covers what the agent reads. To install, start here.

Sources​