Back to CLI

OS-Level Sandbox

The Consilium CLI sandbox isolates every spawned tool from the rest of your machine. On macOS it uses Apple Seatbelt via sandbox-exec. On Linux it uses bubblewrap with unshared mount, PID, and user namespaces. On Windows it falls back to a per-session git worktree with restricted ACLs. Workspaces are gated by a trust file at ~/.consilium/workspace-trust.json.

Why a sandbox?

Anthropic's 2024 research on prompt-injection attacks reported that “agent systems with shell access remain vulnerable to indirect prompt injection even when the top-of-stack model rejects the request, because intermediate tool calls can be hijacked by adversarial content in the workspace.” A workspace-scoped sandbox is the industry-standard mitigation: even if a tool is hijacked, it cannot reach files or hosts outside the approved boundary.

The performance cost is modest. Seatbelt adds ~30-60 ms of startup overhead per spawned process and zero steady-state file I/O overhead because the kernel does the enforcement. Bubblewrap on Linux is even cheaper at ~10-20 ms. Windows pays a one-time ~100-300 ms cost to materialise the worktree at session start.

How is the sandbox implemented on each OS?

OSPrimitiveOverhead
macOSSeatbelt via sandbox-exec~30-60 ms startup
Linuxbubblewrap (bwrap) + namespace unshare~10-20 ms startup
Windowsgit worktree + restricted file ACLs~100-300 ms session create

What does a Seatbelt profile look like (macOS)?

The CLI generates a project-scoped .sb file at session start and passes it to sandbox-exec -f:

(version 1)
(deny default)
(allow process-exec)
(allow process-fork)
(allow file-read*)
(allow file-write* (subpath "/Users/you/myrepo"))
(allow file-write* (subpath "/tmp"))
(allow network-outbound
  (remote ip "api.anthropic.com:443")
  (remote ip "api.openai.com:443"))

What does the bwrap call look like (Linux)?

bwrap \
  --unshare-pid \
  --unshare-user \
  --unshare-net \
  --ro-bind / / \
  --bind /home/you/myrepo /home/you/myrepo \
  --bind /tmp /tmp \
  --proc /proc \
  --dev /dev \
  --share-net \
  --setenv CONSILIUM_SANDBOX 1 \
  -- /usr/local/bin/consilium-tool "$@"

Network is unshared then explicitly re-shared so the CLI can insert a slirp4netns-backed allowlist for outbound LLM API hosts. The mount namespace makes everything outside the workspace read-only.

How is the Windows fallback different?

Windows does not expose a primitive comparable to Seatbelt or user namespaces from userspace. The CLI instead creates a per session git worktree add under ~/.consilium/sandbox/worktree-root and applies restrictive ACLs so the spawned tools see only the worktree, not the original repo. This is weaker than the kernel-enforced sandboxes but still blocks the most common prompt-injection patterns (delete sibling files, exfiltrate from parent directories, modify shell rc files).

How does workspace trust work?

The first time the CLI is launched in a new workspace, it prompts for a trust decision. The choice is persisted to ~/.consilium/workspace-trust.json with one of two levels:

  • always - trusted across restarts. Right level for your own long-lived repos.
  • session - trusted only for the current CLI process. Right level when reviewing untrusted code.
{
  "workspaces": [
    {
      "path": "/Users/you/myrepo",
      "level": "always",
      "trustedAt": "2026-05-20T14:02:31Z"
    },
    {
      "path": "/tmp/review-pr-129",
      "level": "session",
      "trustedAt": "2026-05-20T14:11:18Z"
    }
  ]
}
Trust slash commands (/trust)
/trust listShow every trusted workspace with its level.
/trust addMark the current workspace as trusted. Prompts for always or session.
/trust remove [path]Remove a workspace from the trust file. Defaults to the current cwd.
/trust statusShow whether the current workspace is trusted and at what level.
CLI flags
  • --sandbox - force sandbox enforcement for this invocation, even if the workspace is not trusted.
  • --no-sandbox-strict - downgrade hard blocks to warnings. Useful while iterating on a profile. Never use in CI.

The full implementation (profile generators, trust store, slash command handlers) lives in the public CLI repository: github.com/skadri1601/consilium-cli.