Blog
Sandboxing Coding Agents with macOS Seatbelt: Kernel-Level Protection Without VMs
Autonomous coding agents require local shell access to build and test software, but unconfined execution puts your SSH keys, cloud credentials, and adjacent repositories at risk. macOS Seatbelt lets you confine agents to specific directories at the kernel level without sacrificing native developer performance.
macOS Seatbelt is a kernel-level mandatory access control framework that confines processes using the Sandbox Profile Language (SBPL) via sandbox-exec without the CPU and filesystem overhead of virtual machines or Docker containers. When applied to AI coding agents like Claude Code, Codex, or Forkbench, Seatbelt restricts write operations to designated project directories and temporary folders while blocking reads to sensitive locations such as ~/.ssh and ~/.aws. Profiles are inherited by all child processes including build scripts and npm hooks, and they cannot be escalated or widened from within the sandbox. While Seatbelt provides robust filesystem containment and prevents catastrophic host mutations, complete agent security also requires isolated network controls and sealed credential injection so that raw API keys never enter the sandboxed process environment.
The security dilemma of unconfined coding agents
AI coding agents are fundamentally different from code completion tools because they execute commands directly in your local shell.
Running npm install, cargo build, or automated test suites grants whatever process the agent spawns the exact same permissions as your user account.
A compromised dependency, a hallucinated curl command, or an errant recursive deletion can inspect your ~/.ssh directory, harvest credentials from ~/.aws, or overwrite files across your other projects.
Prompt injection vulnerabilities in agent tooling make this blast radius intolerable for serious engineering work on a primary developer workstation.
Why Docker and microVMs break developer ergonomics
The standard industry response to untrusted code execution is virtualization, wrapping the runtime inside Docker containers or lightweight microVMs.
Virtual machines provide strong isolation boundaries, but they dismantle everyday developer ergonomics on macOS.
Virtio and gRPC filesystem mounts between macOS and Linux virtual machines introduce crippling I/O latency on massive node_modules trees.
Virtualization also breaks local macOS keychain integrations, hardware security keys, Touch ID authentication, and access to pre-installed native toolchains.
Running multiple agent sessions concurrently inside dedicated VMs quickly exhausts system RAM and drains battery life.
What macOS Seatbelt is and how sandbox-exec works
macOS Seatbelt is the mandatory access control architecture built directly into the XNU kernel, originally implemented as a TrustedBSD MAC framework module.
Every sandboxed application on macOS, from Safari renderer processes to system daemons, relies on Seatbelt to enforce operating system boundaries.
The user-space interface is the sandbox-exec command line utility, which compiles human-readable profiles into bytecode and hands enforcement to the kernel.
Modern agent tooling, including Claude Code, Codex CLI, and Forkbench, uses Seatbelt to execute agent commands natively at bare-metal speed while bounding their system reach.
Inside Seatbelt profiles: SBPL and kernel enforcement
Seatbelt rules are authored in the Sandbox Profile Language, a Scheme-based dialect that defines granular allow and deny directives.
A robust agent sandbox operates under a default-deny policy, explicitly enumerating every permitted system call and file path.
File write operations can be locked strictly to the repository root and transient directories like /tmp, while read permissions to sensitive home directory subpaths are denied outright.
Because enforcement happens inside the kernel VFS layer, no user-space interception, shim, or LD_PRELOAD spoofing can bypass the restriction.
- (deny default): Blocks all system calls unless an explicit allow rule matches.
- (allow file-read*): Grants read access across standard system frameworks, libraries, and binaries.
- (deny file-read* (subpath (param "HOME_SSH"))): Forbids reading sensitive keys or authentication configs.
- (allow file-write* (subpath (param "PROJECT_DIR"))): Restricts all filesystem modifications to the targeted repository.
Process inheritance and the non-nesting rule
Seatbelt policies bind to a process at execution and are inherited automatically by every descendant child process.
When an agent executes an npm install script or runs a Makefile, every sub-shell and spawned binary remains bound by the exact same profile constraints.
Crucially, Seatbelt rules cannot be widened or loosened by a sandboxed process, preventing privilege escalation from within.
However, macOS Seatbelt profiles do not nest. Once a process is running under a profile with deny rules, attempting to apply a secondary sandbox inside it fails with an operation not permitted error.
Wrapping your top-level terminal in a custom Seatbelt profile will break the internal sandboxing mechanisms that agents like Codex attempt to apply themselves.
The three boundaries: filesystem, network, and credentials
Filesystem containment is essential, but it is only one component of a complete defensive strategy.
A process restricted from modifying files can still exfiltrate data over the network if socket operations remain unrestricted.
Seatbelt can filter outbound TCP connections by port or host, but fine-grained domain filtering is better handled through dedicated proxy boundaries.
Furthermore, filesystem sandboxes cannot prevent an agent from leaking environment variables or tokens that are passed directly into its process context.
True credential protection requires sealed secret injection, such as Forkbench's encrypted Vault, where agents call authenticated tools without ever possessing the underlying raw secret.
Related: MCP server security risks and secrets in configuration, Agent Client Protocol: client terminal permissions and isolation, Forkbench security architecture and vault isolation, Multi-agent coordination on the Forkbench Teamwork board
Frequently asked
Is sandbox-exec deprecated on modern macOS versions?
Apple marked the sandbox-exec CLI tool as deprecated in macOS man pages, but the underlying Seatbelt kernel framework remains the foundational security boundary for App Sandbox and system services across all current versions of macOS. It remains fully functional and reliable for CLI sandboxing.
Can an agent escape a macOS Seatbelt sandbox?
Seatbelt is enforced directly inside the XNU kernel by Apple's TrustedBSD MAC framework, so escaping it requires an unpatched privilege escalation kernel exploit. User-space programs and build scripts cannot override kernel-level denials.
Why does wrapping an agent terminal in sandbox-exec cause errors?
macOS Seatbelt profiles do not support nesting. If an outer shell is already executing under a profile containing deny rules, any child process attempting to apply its own sandbox-exec profile fails immediately with an Operation not permitted error.
Does macOS Seatbelt protect API keys in my environment variables?
No. Seatbelt enforces filesystem, process, and network access boundaries, but it does not redact process environment variables or memory contents. Protecting API keys requires a vault architecture (such as Forkbench Vault) where secrets are injected dynamically or managed through mediator tools.