← Blog · · Nick Stocks

Docker Is Not a Sandbox: Why MCP Server Isolation Needs gVisor

Docker containers share the host kernel. Namespace isolation is not a security boundary. For MCP servers running untrusted code, kernel-level isolation via gVisor is the difference between a blast radius of one container and full host compromise.

security mcp sandbox gvisor docker infrastructure
Docker Is Not a Sandbox: Why MCP Server Isolation Needs gVisor

Docker containers are not sandboxes. They are isolated processes that share your host kernel. For MCP servers running third-party or user-uploaded code, that distinction is the difference between a contained incident and a full host compromise.

Start for free → | Setup guide →


There's a widely held assumption in the AI infrastructure world: put your MCP server in a Docker container, and you've sandboxed it. You haven't.

Docker is an excellent tool for packaging and deploying software. It is not a security boundary. If you're running untrusted MCP server code in Docker and calling it sandboxed, you've accepted a risk you may not fully understand.

This post explains what Docker actually provides, what it doesn't, and why kernel-level isolation via gVisor changes the threat model for MCP server hosting.


What Docker Actually Provides

Docker uses two Linux kernel features to isolate containers: namespaces and cgroups.

Namespaces give each container its own view of the system — its own process tree, network stack, filesystem mount points, and hostname. From inside the container, it looks like a separate machine.

Cgroups limit how much CPU, memory, and I/O a container can consume. They prevent resource exhaustion but don't restrict what the container can do at the kernel level.

What both of these have in common: they are provided by the host kernel, and the container communicates with that same host kernel directly.

Every system call a process makes inside a Docker container — open(), mmap(), ptrace(), socket() — goes to the real host kernel. There is no intermediary. There is no second kernel. The container's process talks directly to the kernel that runs your entire host.

The diagram above shows this split clearly. On the left, a Docker container with standard namespace isolation: the syscall surface is wide open to the host kernel. On the right, gVisor's model: a user-space kernel sits between the container and the host.


Why That Matters for MCP Servers

An MCP server is code — often written by a third party, sometimes uploaded by a user, always executing with some degree of privilege. In the MCP ecosystem today, plugin authors range from major vendors to individual developers with varying security practices. Supply chain attacks targeting developer tooling are documented and increasing.

If an MCP server process is compromised — whether through a known CVE in a dependency, a supply chain attack, or malicious code that was always malicious — the attacker controls a process that has direct access to your host kernel.

The host kernel exposes over 300 system calls to a standard Docker container. A sufficiently crafted kernel exploit targeting any one of those can break out of the container entirely, gaining access to the host system. Container escapes via kernel vulnerabilities are not theoretical: CVE-2022-0492 (Palo Alto Networks Unit 42, 2022) and CVE-2024-1086 (NIST NVD, 2024) are recent examples of Linux kernel vulnerabilities that could be exploited to escape container isolation. A kernel exploit that reaches the real host kernel doesn't stay in one container.


What gVisor Does Differently

gVisor is an open-source project released by Google in 2018. It provides a user-space kernel called the Sentry.

When a containerised process makes a system call, instead of that call going to the host kernel, it goes to the Sentry — a Go process running in user space that implements the Linux system call interface. The Sentry handles the call, enforces its own security policy, and only reaches the real host kernel for a small set of operations it can't avoid.

That small set is approximately 20 host syscalls, accessed via a separate process called the Gofer. Standard Docker exposes 300+.

The reduction looks like this:

Isolation model Host syscalls exposed
Standard Docker container 300+
Docker + seccomp filter (restrictive) ~50–100
gVisor (runsc) ~20

Even with a restrictive seccomp profile, the attack surface remains substantially larger than gVisor's model. With no seccomp policy — which is the default for most Docker deployments — a container has access to the full kernel interface.

Google has documented using gVisor in production for running untrusted workloads. Their security overview covers the threat model in detail.


The MCP Threat Model With and Without gVisor

Consider a concrete scenario: an MCP server has a dependency with a known remote code execution CVE. An attacker exploits it and achieves arbitrary code execution inside the container.

With standard Docker: The attacker's code runs inside a container that shares the host kernel. They can attempt to use kernel vulnerabilities, write to /proc entries that affect host state, or exploit misconfigurations in the namespace setup. If successful, they're on the host — with access to every other container, the filesystem, network, and credentials in the environment.

With gVisor: The attacker's code runs inside a container whose kernel is the Sentry. Any attempt to use a host kernel vulnerability is blocked at the Sentry boundary — the host kernel syscalls the Sentry uses are a narrow, controlled set that doesn't expose the broader attack surface. The blast radius stays inside the container.

The Sentry is not invulnerable. A vulnerability in the Sentry itself could, in principle, be exploited. But the Sentry is a substantially smaller and more auditable codebase than the Linux kernel, and its design deliberately limits what it can do at the host level.


Defence in Depth: gVisor Is One Layer

Kernel isolation addresses one part of the threat model. It doesn't address everything.

A compromised MCP server that can't exploit the host kernel can still attempt to exfiltrate data over the network, abuse the credentials injected into its environment, or send malicious responses back to the agent calling it.

That's why mistaike.ai's hosted MCP sandbox combines multiple independent layers:

gVisor (runsc runtime) — limits kernel syscall surface to ~20 host calls. Kernel exploit attempts hit the Sentry, not your host.

Default-deny egress via Envoy — each MCP server declares the external domains it requires (max 10, FQDNs only, no wildcards). All other outbound traffic is blocked. An attacker that achieves code execution can't beacon out to arbitrary infrastructure.

Bidirectional DLP — every tool call and every response is scanned before it moves. Credentials and PII are caught in both directions.

Ephemeral containers — five minutes idle, the container is destroyed and replaced with a fresh instance. No persistent foothold.

These layers are independent. gVisor limits what the process can do at the kernel level. Envoy limits what it can reach on the network. Neither replaces the other. Both are necessary.

The diagram above shows how these sit relative to each other: gVisor between the container and the host kernel, Envoy on the network path out.


Why This Matters Now

The MCP ecosystem is growing faster than its security practices. Developers are connecting agents to community-built servers, user-uploaded code, and rapidly iterated plugins. The assumption that "Docker is good enough" is widespread and understandable — Docker is genuinely excellent for most use cases.

But MCP server hosting is a specific threat model: you are running code written by someone you don't fully control, on infrastructure you do control, processing data that may be sensitive. That threat model benefits from kernel-level isolation in a way that generic containerised web services don't.

Running a blog on Docker? Namespace isolation is fine. Running a third-party MCP server that processes your users' financial data? The kernel attack surface is worth reducing.


How to Use gVisor

gVisor is open-source and available at gvisor.dev. The runsc runtime can be configured as a Docker runtime with a few lines of configuration.

If you want MCP servers running under gVisor without configuring it yourself, mistaike.ai's hosted sandbox does this by default. Every server you upload runs under runsc, with default-deny egress, DLP on every call, and ephemeral containers. You get the isolation model without managing the infrastructure.

Read the setup guide → | See the full security architecture →


Summary

  • Docker namespaces and cgroups provide process isolation, not kernel isolation
  • Container processes communicate directly with the host kernel — 300+ syscalls are reachable
  • A kernel exploit from inside a standard Docker container reaches the real host kernel
  • gVisor interposes a user-space kernel (the Sentry) between the container and the host
  • The Sentry limits host kernel exposure to ~20 syscalls via the Gofer process
  • For MCP servers running untrusted code, this substantially reduces the blast radius of a kernel-level attack
  • Kernel isolation is one layer — it works alongside network controls and DLP, not instead of them

Start for free → | Read the setup guide → | See the full security architecture →


Nick Stocks is the founder of mistaike.ai.