In April 2026, security researchers disclosed a remote-code-execution flaw baked directly into Anthropic's official Model Context Protocol SDK — every language binding, Python, TypeScript, Java, Rust. The bug sat in how the STDIO transport handled server configuration: it passed parameters straight to the host shell with no sanitization. Feed it the wrong string and you didn't get a tool call, you got a shell. By the time the advisory went out, more than 7,000 public MCP servers and upwards of 150 million package downloads were implicated, with an estimated 200,000 vulnerable instances scattered across the ecosystem.
Anthropic's response was blunt: this is how the protocol was designed to work, and it isn't changing. Which means the fix for anyone building on MCP was never going to come from the protocol layer. It has to come from what happens around the tool call — and Docker had already shipped an answer.
If your MCP tool server is just a chat plugin fetching stock quotes, an unsandboxed RCE is bad. If it's the MCP server sitting in front of your deploy pipeline — the one an agent calls to ship, roll back, scale, or tail logs on production — an unsandboxed RCE isn't a leaked API response. It's an agent's tool call turning into arbitrary code execution on the box that runs your infrastructure. That's the gap this post is about closing.
What Docker's MCP Gateway actually locks down, per tool call
Docker's MCP Gateway doesn't run MCP servers as trusted local processes with shell access. It launches each one as its own container, with a fixed set of constraints applied before the first tool call is ever accepted:
| Control | Default | What it stops |
|---|---|---|
| CPU | 1 core | A compromised tool server can't consume the host's compute to pivot or crypto-mine |
| Memory | 2GB | Bounds the blast radius of a memory-exhaustion or runaway-process bug |
| Privilege escalation | --security-opt no-new-privileges | Blocks a container process from gaining more privilege than it started with, even via setuid binaries |
| Filesystem | No host mounts by default | A compromised tool can't read or write anything outside its own container |
| Network | Restricted/default-deny egress | Exfiltration and lateral movement require an explicit egress rule, not ambient access |
| Image provenance | docker mcp gateway run --verify-signatures against build attestations + signed SBOMs | A malicious or tampered catalog image fails to start rather than silently running |
| Payload inspection | --block-secrets interceptor | Inbound/outbound tool payloads are scanned and secrets are stripped before they cross the wire |
None of these are exotic. They're the same primitives every container platform ships — cgroup limits, seccomp/no-new-privileges, network policies, image signing. What's notable is that Docker applies the full stack of them, by default, per MCP tool server — not as an opt-in hardening guide someone has to go implement, but as the shape the gateway ships in. The STDIO RCE we opened with is a command-injection bug that hands an attacker a shell. Inside Docker's model, that shell exists in a container with one CPU core, 2GB of memory, no host filesystem, and no network path out by default. The bug isn't patched — but its blast radius is the container, not the host.
One gateway, not forty trust decisions
The other half of the model is architectural, not just per-container hardening. Docker's catalog lists over 100 verified MCP servers from partners like Stripe, Elastic, and Neo4j, and the Gateway's job is to put all of them — plus whatever community servers you add — behind one process that enforces the table above uniformly. Instead of forty tool integrations each making their own ad hoc call about sandboxing, secrets, and network access, there's a single auditable choke point where every tool call passes through the same policy.
That choke point is also where interceptors sit — programmable pre-call and post-call filters. A pre-call interceptor can reject a tool call whose arguments look like a path-traversal or shell-injection attempt before it ever reaches the container. A post-call interceptor can redact PII or block a response that contains something that looks like a credential. This is the part that a bag of per-container resource limits doesn't give you on its own: a place to write policy once and have it apply to every tool, every call, without touching each server's implementation.
Applying it to a deploy-from-chat MCP server
Here's where it stops being a Docker feature and becomes a design requirement for anyone building an agent-facing MCP server that can actually change production — the exact position a git-push PaaS's own MCP server occupies when it exposes deploy, rollback, scale, and logs as callable tools.
The mistake is treating those four tools as endpoints on one already-trusted internal service, reachable because the caller authenticated once. The Docker model says: every call, not just every server, is the unit of containment. A rollback command an agent constructs from a hallucinated argument should fail the same way a hallucinated shell command in a sandboxed MCP server fails — contained to a resource-capped, network-restricted container — not execute directly against your control plane's credentials.
But copying Docker's 1 CPU / 2GB default onto every one of those tools uniformly is the wrong move. The generic default is sized for a stateless read-a-webpage or query-a-database tool call that finishes in milliseconds. Deploy tooling doesn't look like that:
| Tool | Where the generic default breaks | What to size instead |
|---|---|---|
deploy | Triggers a build — CPU-bound, can run minutes, not milliseconds | Higher CPU ceiling, longer timeout, but still no host filesystem access — the build runs in its own scoped workspace, not on the gateway host |
rollback | Needs write access to one specific piece of state (the routing/version pointer), not the filesystem | Keep the tight CPU/memory cap; grant a narrow, scoped write credential instead of broad network egress |
scale | Needs API write scope to the orchestrator, nothing else | Tightest cap of the four — no filesystem, no outbound network beyond the one internal API endpoint |
logs-tail | Long-lived streaming connection, not a single request/response | Low CPU is fine, but the network-egress default has to allow a persistent connection, scoped to exactly one log-source endpoint |
The point isn't the specific numbers — it's that "steal Docker's model" means stealing the practice of setting an explicit, minimal ceiling per tool call and defaulting to deny beyond it, not copy-pasting one number onto four tools with different workloads. Get that wrong in either direction — too loose, and a hallucinated or injected call gets more blast radius than the tool needs; too tight, and deploy times out mid-build — and the containment model stops matching what the tools actually do.
Signing and provenance carry over unmodified, though: a platform's own deploy/rollback tool images should be built and verified the same way Docker verifies catalog entries — signed, attested, checked at gateway startup — so an agent calling rollback is provably invoking the code you shipped, not a tampered image that shipped something else. And every call — successful or rejected — should produce one audit log line: which tool, which arguments, which container, which outcome. When the call in question can roll back production, "we don't have a record of what the agent actually sent" is not an acceptable gap.
The blast radius is the whole point
The April 2026 MCP RCE didn't get fixed at the protocol layer, and Anthropic has said it doesn't intend to. That means the containment has to live in the layer every MCP deployment controls directly: how the tool server is run, not how the protocol is specified. Docker's Gateway is a working reference for what that containment looks like in production — concrete resource ceilings, default-deny network and filesystem, signed images, and one auditable proxy in front of all of it.
For a chat-driven deploy pipeline, that reference isn't optional hardening to bolt on later. An agent that can deploy, roll back, and scale your infrastructure by calling tools is exactly the kind of MCP server where "the tool implementation trusts its own inputs" is the difference between an agent making a mistake and an agent doing arbitrary damage to the host it's running on.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with agents as first-class operators via a Render-compatible API. Designing an MCP server that exposes deploy/rollback/scale safely is exactly the kind of problem we build for. Star the repo on GitHub or deploy your first app today.
Sources
- Docker: MCP Gateway documentation
- Docker: MCP Security — Risks, Challenges, and How to Mitigate
- Docker: Introducing Docker MCP Catalog and Toolkit
- Docker: MCP Toolkit and Gateway, Explained
- GitHub: docker/mcp-gateway
- The Hacker News: Anthropic MCP Design Vulnerability Enables RCE, Threatening AI Supply Chain
- Tom's Hardware: Anthropic's Model Context Protocol includes a critical remote code execution vulnerability
- OX Security: MCP STDIO Command Injection — Full Vulnerability Advisory