Skip to content

Defense-in-depth: spawn-time sandbox for project-local MCP servers #599

Description

@griffinwork40

Follow-up from #571 (deferred there as explicitly out of scope).

Context

#571 closed the consent gap: project-local <cwd>/.mcp.json no longer auto-spawns arbitrary commands (now opt-in via AFK_ALLOW_PROJECT_MCP). But consent is not containment — once an operator opts in (AFK_ALLOW_PROJECT_MCP=1), a project-local stdio server still spawns with the full ambient privileges of the AFK process: unrestricted filesystem write, network egress, and access to the operator's environment.

Why this matters

A project server's env block can reference ${SECRET} via the live expander (src/agent/mcp/env.ts), landing operator secrets in the child's environment. Even a trusted opt-in server is a large blast radius if it (or a dependency it shells out to) is later compromised — e.g. an npx pkg@latest-style command resolving to swapped code after a registry push (the exact reason #571 rejected a JSON-hash trust store).

Proposed control (separate from consent)

Restrict what a project-local (and ideally any) stdio MCP server can do at spawn time:

  • scrub / allowlist the env handed to the child (don't forward the full process.env; require explicit passthrough);
  • optional network-egress and fs-write restrictions where the OS supports it (per-OS cost — likely sandbox-exec on macOS, seccomp/bubblewrap on Linux, best-effort elsewhere);
  • surface the granted capabilities in the startup notice.

Spawn chokepoint: src/agent/mcp/transport.ts (new StdioClientTransport), fed by McpManager.fromConfig (src/agent/mcp/manager.ts).

Acceptance (rough)

  • Project-local stdio servers spawn with a scrubbed/allowlisted env by default.
  • Documented, opt-in escape hatch for servers that genuinely need passthrough.
  • Per-OS containment where feasible; graceful degradation elsewhere with a clear notice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions