ADR-026: OS-Native Process Sandboxing Architecture

Context

MCP servers run as local processes with full user privileges — installing one is equivalent to running arbitrary code. The MCP spec recommends running servers in sandboxed environments but doesn't mandate any mechanism. Real-world MCP security incidents in 2025 (10+ CVEs including RCEs and sandbox escapes) make process isolation a pressing concern.

Gatekit is uniquely positioned to add sandboxing: as the gateway that spawns MCP server processes, it can transparently wrap commands with OS-native sandboxing before process creation.

Requirements

  1. Simple per-server toggle that "just works" with sensible defaults
  2. Advanced users can customize filesystem and network policy via YAML
  3. No Docker dependency — must work on a bare development machine
  4. Fail-closed: if sandbox is enabled but unavailable, refuse to start the server
  5. Must not break process lifecycle management (killpg, graceful shutdown)

Decision

OS-native sandboxing, not containers

We chose OS-native sandboxing mechanisms over Docker/Podman because:

Engine selection

macOS: Seatbelt (sandbox-exec)

Linux: bubblewrap (bwrap)

Alternatives evaluated and rejected:

Core infrastructure, not a plugin

Sandboxing operates at the process level, before any MCP messages flow. It wraps the command passed to asyncio.create_subprocess_exec(). This is fundamentally different from plugins which operate on messages. Making it a plugin would require the plugin to have control over process creation, which violates the transport abstraction.

Stdio transport only

HTTP transport servers are remote — Gatekit doesn't control their process. Sandboxing only makes sense for locally-spawned stdio processes.

Default security policy

Consequences

Positive

Negative

Risks

Status

Accepted