The MCP audit checklist your team needs this week
Anthropic says the protocol behaves as designed. OX Security says two hundred thousand instances are exposed. Both are true, and your install path needs an audit before either statement matters to you
Last week we wrote about what MCP gives you. This week the question is what you give up. The two are the same protocol, the same install paths, and the same set of binaries running on your laptop with your privileges. It's just that the answer changes when you stop counting features and start counting trust boundaries.
On 15 April 2026 OX Security published an advisory describing a command-injection design in MCP's STDIO transport, the path most local servers use. Their headline numbers: more than seven thousand publicly exposed servers, downloads in the hundreds of millions, up to two hundred thousand vulnerable instances reachable. Ten CVEs got assigned downstream, including CVE-2026-30623 against LiteLLM and CVE-2026-30615 against Windsurf. Anthropic's response was that the behaviour "is by design" and that "sanitisation is the developer's responsibility".
Both of those statements are correct. Both can be acted on. Neither is an excuse to skip an audit.
What the disclosure actually says, in plain English
The protocol's STDIO transport works by spawning a server binary as a subprocess and passing arguments through a shell. If a configuration file lets user-controllable input flow into those arguments, an attacker who can influence that configuration can run arbitrary commands on the host. The model never has to be tricked. The IDE never has to be exploited. The shell does what shells do.
The reason Anthropic can call it "by design" is that this is genuinely the way local subprocess plumbing works on every operating system. A protocol that forbids it would have to forbid local subprocesses, which would gut the local-tool story MCP exists to enable. The reason OX can call it a vulnerability is that the design assumes a level of input hygiene that most real configurations don't have, and the blast radius when hygiene fails is RCE on a developer laptop.
The "by design" trap
"By design" is technically defensible and operationally explosive. It's true that the protocol behaves as specified. It's also true that the developer holding the bag is you, and that the threat model "I will sanitise every configuration touching my MCP servers correctly, every time, forever" is the kind of statement security people retire on.
The threat model, named honestly
Three realistic paths to compromise, in roughly descending order of probability:
- Supply-chain. You install an MCP server from a public registry. The package is genuine on day one and gets a malicious update on day forty. Your agent runs it on day forty-one. This is the boring CVE path: typical npm or PyPI compromise, except the binary now has access to whatever your agent can reach.
- Configuration injection. Your MCP server takes arguments derived from project files (a workspace path, a test target, a database name) and a teammate commits a malicious value into a shared config. Your agent picks it up on next launch and the shell expansion does the rest.
- Server-as-broker. A server you trust calls a tool it shouldn't. A search server fetches an attacker-controlled page; a parsing routine downstream of that fetch decides part of the page is a "command" and asks the model to act on it. This is the prompt-injection-as-RCE story, and it's the one where being careful at install time helps least.
Most published exploitation paths track to the first or the second. The third is real but harder to pin to a single CVE because it depends on what the chained tools do.
The audit checklist, before you wire anything up
This is the list to walk through for any MCP server before you add it to your config. Forty-five minutes per server, the first time. Five minutes for each subsequent version bump. If a server fails any of these, you don't add it; you find another way.
1. Who publishes it, and from where
Open the registry page. Find the publishing organisation. Confirm it's the project's actual maintainer, not a typosquat or a fork that diverged six months ago. Look at the source repository. If the README points at a registry name and the registry name points at a different repository, stop.
2. What does the binary actually call
Read the source. You're looking for two things: every place the server shells out (any spawn, exec, or subprocess invocation that touches a shell) and every place a tool argument flows into one of those calls. If a tool takes a string and that string ends up in a shell, the input must be escaped, not concatenated. If you can't tell, treat the server as untrusted.
3. What is the launcher
LiteLLM's post-disclosure remediation now refuses to launch any STDIO server whose command isn't on a tight allowlist (npx, uvx, python, python3, node, docker, deno) unless you opt the binary in via LITELLM_MCP_STDIO_EXTRA_COMMANDS. Other clients are converging on similar restrictions. If your client doesn't, set up the equivalent yourself: a single launcher per server type, no shell wrappers, no bash -c.
// bad: shell wrapper, expansion happens before the launcher sees the args "command": "bash" "args": ["-c", "my-mcp-server $WORKSPACE_PATH"] // good: direct launcher, args are an array, no shell in the loop "command": "npx" "args": ["-y", "@my-org/mcp-server", "--workspace", "/abs/path/to/repo"]
4. What data does it actually touch
Filesystem servers should be sandboxed to a project root, not $HOME. Database servers should point at a non-production replica with read-only credentials, not your production primary. Network servers should have an explicit allow-list of hosts they're allowed to fetch. If the server's documentation doesn't tell you how to scope it, that's a finding.
5. Version pinning and update path
Pin to a specific version (a tag or a content hash), not latest. Set a calendar reminder to review updates monthly. Yes, this means you'll fall behind. Falling behind is fine; auto-pulling a compromised latest at next agent launch is not.
6. Isolation when in doubt
If a server has to run untrusted-feeling, run it in a container or a separate user account with no access to the rest of your machine. Docker is on the LiteLLM allowlist for a reason. The cost of running an MCP server in a container is twenty seconds of startup; the cost of running it as you on your dev box is whatever it can reach.
7. Audit the config itself, not just the server
The config file is the attack surface. ~/.cursor/mcp.json, Claude Code's config.toml, VS Code's settings.json: read them. Check that no values come from environment variables your shell rc could rewrite. Check that no path is a relative one that could resolve into a project-controlled location. Check that the config file itself isn't writable by anyone other than you.
What good looks like, on a real laptop
The end state isn't a fortress; it's a small, named, audited surface. For most teams, this is the working shape:
- Five servers maximum, all installed deliberately, all on the canonical team list.
- Direct launchers only (no
bash -c, no environment-variable expansion in the launcher line). - Version-pinned to a hash or a tag, with a monthly review cadence.
- Filesystem servers sandboxed to project roots, never
$HOME. - Database servers on read-only replicas, never production primaries.
- One owner on the team for the canonical config, with the file under version control inside a private repo.
That's it. None of this is exotic. All of it is the kind of discipline you'd apply to any tool that gets to read your filesystem and your database, which is what an MCP server is. The reason it feels new is that nobody calls these tools "shells with editor integrations", which is what they functionally are.
Where this goes next
The 2026 MCP roadmap items we mentioned last week (stateful sessions, .well-known metadata, SSO-integrated auth) all bear on this directly. .well-known lets a client discover what a server claims to do without trusting documentation. SSO-integrated auth means the server enforces who you are rather than trusting whoever runs the binary. None of those are shipped to general availability yet. Until they are, the audit checklist is what stands between an MCP install and a CVE filing in your name.
Pinterest's production deployment, the most visible enterprise example we've seen, runs essentially this discipline at scale: a central registry every server must register against, two-layer authorisation combining end-user JWTs with service-mesh identities, and human-in-the-loop approval for sensitive operations. That's not a plug for Pinterest's architecture; it's a plug for the realisation that an MCP fleet you can defend looks like an MCP fleet you've governed, not an MCP fleet you've discovered.
Anthropic isn't wrong that the protocol works as designed. OX isn't wrong that two hundred thousand instances are exposed. The thing that resolves the apparent contradiction is the install path between the two, and that path is yours. Audit before you wire up. Pin versions. Sandbox filesystems. Keep the server count small enough that you can name every one. The convenience is real. So is the trust boundary you just moved.