DEV Community

Ben Bar lev
Ben Bar lev

Posted on

The MCP stdio launch boundary is the authorization decision everyone skips

The MCP stdio launch boundary is the authorization decision everyone skips

A running MCP server does not have a useful authorization surface left to retrofit. By the time tools/call arrives, the process already holds host privileges. The decision that actually separates "a tool that runs commands" from "an attacker who runs commands" happens one step earlier, before the process exists: is this server allowed to launch at all, at this command+args+env, under this delegation, approved by whom?

Most agent-security writing frames the problem backwards. It asks "how do I authorize each tool call?" But the tool call happens inside a process the host already spawned with full privileges. A per-call gate inside that process is a speed bump inside the blast radius, not a boundary.

Evidence this is real (all verified, mid-2026)

  • CVE-2026-46519 (mcp-server-kubernetes, fixed v3.6.0): the access-control env vars (ALLOWED_TOOLS, ALLOW_ONLY_READONLY_TOOLS, ...) were enforced in the tools/list presentation handler but absent from tools/call execution. A client could call any tool by name regardless of restriction, including kubectl_delete and exec_in_pod. Tools/list filtering was cosmetic; the call layer disagreed. Confirmed on NVD, GitHub Advisory GHSA-cr22-wjx7-2w6m.
  • CVE-2026-85660 (cli-mcp-server, CVSS 9.2 critical): command allowlist bypass via shell substitution when ALLOW_SHELL_OPERATORS was on. The allowlist is checked somewhere, but craft the input and the check is gone.
  • The CSA stdio design flaw (CVE-2026-30623 LiteLLM, CVE-2026-33224 Bisheng, CVE-2026-40933 Flowise): the MCP SDKs pass the config command string to the shell unconditionally. The command executes even when the target process fails to start. CSA research estimates 150M package downloads, ~7,000 publicly reachable servers, ~200,000 vulnerable deployments, and 14+ CVEs. Anthropic characterized the behavior as "expected" and left sanitization to downstream developers.

Two concrete failure shapes, both upstream of any tool-call gate:

  1. Configuration-as-supply-chain. A compromised npm/PyPI package, a seeded editor config, a PR that helps add a useful server: anything that writes command to an MCP config now has an unauthenticated path to arbitrary shell execution at next launch. No model involved.
  2. Presentation vs execution desync (CVE-2026-46519). The deployer believes the server is least-privilege because the tool list says so; the call layer disagrees.

The default-deny pre-spawn model

Govern the launch, not just the calls. Before the host forks the server:

  1. Decide. Is this (server, command path, args, env, run-as identity) on the allowlist? Hardcoded absolute binary path, not a derived string.
  2. Bind to delegation. This launch is authorized by this user + this agent + this scoped purpose, not "whoever's editor is open."
  3. Approve. A human gate for any server that reaches shell, credentials, or files (the tier-0 supply-chain class), same as a production change.
  4. Record before effect. Emit a decision record (who, what, which identity, approved-by) before spawn, so the launch itself is auditable and not reconstructed from a log afterward.

If the caller cannot show an explicit allow plus a recorded approval for the exact command about to execute, deny. Default-deny is the only posture consistent with treating a shell-exec as a privileged action.

What a good implementation looks like

Separate the decision (client/agent side) from the effect (the spawned process), so they cannot drift the way CVE-2026-46519's list and call layers drifted. Anchor the decision record out-of-band, independent of the server under audit, and recomputable on replay. Disable stdio where a governed HTTP transport suffices (this is the CSA guidance), and keep stdio only where the per-client process boundary is itself wanted (signing, key access), then gate the launch.

Honest scope: this is guidance and a runtime shape, not a claim that one product solves it end to end. AgentKey implements the authz-plus-evidence runtime boundary, per-call decision records bound to identity and args plus recomputable evidence. The pre-spawn launch gate is the layer upstream that protocol designers declined to standardize. https://agentkey.us

Sources: NVD CVE-2026-46519, CVE-2026-85660, CVE-2026-30623, CVE-2026-40933; GitHub Security Advisory GHSA-cr22-wjx7-2w6m; CSA research note on the MCP stdio design flaw (Apr 2026); VulnCheck advisory for cli-mcp-server.

Top comments (0)