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.
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?
| OS | Primitive | Overhead |
|---|---|---|
| macOS | Seatbelt via sandbox-exec | ~30-60 ms startup |
| Linux | bubblewrap (bwrap) + namespace unshare | ~10-20 ms startup |
| Windows | git 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 list | Show every trusted workspace with its level. |
| /trust add | Mark 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 status | Show whether the current workspace is trusted and at what level. |
--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.