Skip to content

Process-Level Sandboxing

Status: Proposed — research captured, no implementation committed

Jackin’s current isolation model operates at two coarse granularities:

  • Git-level isolation (shipped): shared | worktree | clone modes control how each mount is materialized per agent session. This governs filesystem branching, not command-level access control.
  • Runtime-level isolation (deferred): dind | microvm modes determine which compute boundary the entire workspace runs inside. This governs the VM or container boundary, not individual operations inside it.

Neither layer addresses the gap in between: individual tool calls made by an agent during a session have unrestricted access to everything inside their sandbox boundary.

When an agent runs npm install to set up a project, that process can read ~/.ssh/id_rsa, write to /etc, reach arbitrary network endpoints, and inherit every secret injected at container launch. When an agent generates and runs a shell snippet it composed itself, that snippet runs with the same trust level as the entrypoint. There is no per-operation access control — the entire container or VM is the trust boundary, and once the agent is inside it, every subprocess inherits the same permissions.

This is the gap process-level sandboxing fills. It sits below the container/VM boundary, wrapping individual commands in OS-native isolation so that each operation gets only the access it needs.

A complete isolation strategy for AI-agent workspaces has at least three tiers:

Tier Boundary granularity Overhead
─────────────────────────────────────────────────────────────────
Process sandbox Per operation < 10 ms
Container / DinD Per workspace session 100–500 ms
MicroVM Per workspace session 1–5 s

The selectable sandbox backends roadmap item covers the container-to-microVM step. This item covers the process sandbox tier — the innermost ring that wraps individual shell commands, build steps, and AI-generated code invocations.

The two tiers are complementary, not competing. A microVM boundary prevents a container escape from reaching the host. A process sandbox prevents a single bad command from reading every secret inside the VM.

Zerobox is a lightweight, cross-platform process sandboxing tool written in Rust. It originates from OpenAI’s production Codex sandbox runtime and is now open source.

Zerobox executes a command with deny-by-default access controls:

  • Filesystem: reads and writes are blocked unless explicitly permitted via --allow-read, --allow-write, --deny-read, --deny-write path flags.
  • Network: all outbound connections are blocked unless the target domain is listed via --allow-net. Restricted to named domains, not IP ranges.
  • Environment: only a minimal set of variables (PATH, HOME, TMPDIR) pass through by default. Secrets injected at container launch are invisible to sandboxed subprocesses.
  • Credential injection: a built-in network proxy intercepts outbound HTTPS connections and substitutes real API keys at the proxy layer, so the sandboxed process never sees the real credential values. The process sends requests using placeholder values; the proxy rewrites them to the real tokens only for approved host names. This is the same architecture Docker Sandboxes uses for credential isolation.

The overhead is roughly 10 ms per invocation and about 7 MB of memory. There is no daemon, no separate container layer, no image build step.

PlatformMechanism
LinuxBubblewrap (unprivileged user namespaces), Seccomp (syscall filtering), Landlock (kernel 5.13+, filesystem restrictions via LSM)
macOSApple Seatbelt (sandbox-exec, available since macOS 10.5)
WindowsPlanned (restricted tokens + ACLs + firewall rules)

On Linux, the combination of Bubblewrap + Seccomp + Landlock creates defense-in-depth without requiring root or a privileged sidecar. On macOS, Seatbelt runs kernel-enforced policy without any extra dependencies. Neither path uses a container engine — process sandboxing and container isolation compose independently.

Zerobox includes a snapshot module (Blake3 + Merkle trees + LZ4 compression) that can capture filesystem state before a command runs and restore it afterward. This is relevant to the session snapshot and rollback roadmap item: a lightweight, per-operation snapshot is faster and cheaper than a full container or VM checkpoint and is sufficient for many “undo the last build step” use cases.

Zerobox is in early active development (v0.2.x as of May 2026, roughly 580 GitHub stars, daily release cadence). It is not yet production-stable. APIs may change. The Rust SDK (zerobox crate), TypeScript SDK (npm zerobox), and Python SDK (PyPI zerobox) are all available.

Given the pre-1.0 state, the right posture for Jackin is to track zerobox and treat it as a reference implementation that defines the architecture — not to depend on it as a pinned production dependency today.

OpenAI’s Codex CLI runs each shell command it issues through a process sandbox in its default suggest mode and in full-auto mode. The underlying runtime is zerobox: when Codex CLI tells the user it is running a command in “sandbox mode”, it is invoking zerobox with a policy derived from the workspace’s declared network allow-list and the set of paths Codex is currently working in.

This is the production pattern worth understanding for Jackin:

  • The agent entrypoint (Claude Code, Codex, Amp) runs with normal container permissions.
  • Each tool call (shell command, file write, subprocess) is wrapped in a process sandbox scoped to the minimal access that operation requires.
  • The agent’s session continues uninterrupted; only the individual subprocess is sandboxed.

The result is that an agent can run thousands of sandboxed tool calls per session with negligible overhead, while a single miscoded command cannot read a secret or exfiltrate data to an untrusted host.

The selectable sandbox backends item is deferred — it requires a dedicated design pass, a backend abstraction layer, and per-provider integration work. Process-level sandboxing can be adopted today, inside the existing DinD container, without waiting for the microVM track to land.

The two improvements address different attack surfaces:

ScenarioContainer boundary helps?Process sandbox helps?
Agent escapes container to hostYes (microVM closes this further)No
Agent’s tool call reads a secret it shouldn’tNoYes
Agent’s tool call writes to an unrelated pathNoYes
Agent’s tool call phones home to a malicious endpointPartially (no per-operation policy)Yes (per-operation network allowlist)
Agent’s build step corrupts workspace stateNoYes (snapshot + rollback)

Process sandboxing is the layer that controls what individual operations can do inside the sandbox, complementing the layer that controls what the sandbox can see of the host.

This section captures early thinking on how process-level sandboxing could surface in Jackin. It is not a committed design.

The construct image and runtime entrypoint could install a sandboxing shim and configure the agent runtime to route shell executions through it. For Claude Code, this aligns with its --dangerously-skip-permissions full-auto model: the agent still runs without interactive permission prompts, but each shell command it issues is constrained by a Jackin-managed sandbox policy rather than running unrestricted.

Jackin already knows, per workspace mount, which host paths are shared and with what intent. A natural extension is to derive a per-mount process-sandbox policy from the same mount configuration:

[[mounts]]
path = "~/Projects/my-service"
# read-write access → allow-write for this path
# nothing else → deny writes elsewhere
[[mounts]]
path = "~/Projects/shared-libs"
readonly = true
# read-only access → allow-read for this path, deny-write

The sandbox policy for any command running against these mounts would be derived automatically: allow writes to ~/Projects/my-service, allow reads from ~/Projects/shared-libs, deny everything else.

Zerobox’s built-in network proxy implements the same credential injection architecture that Docker Sandboxes uses: secrets never enter the sandboxed process; the proxy substitutes them only for approved host names. This is a direct implementation path for the credential proxy item in the security roadmap. Rather than building a standalone proxy, Jackin could delegate this to the process sandbox layer for commands that run inside the agent session.

Some agents (role repos that invoke Docker to build sibling containers) issue Docker CLI commands as part of their workflow. These could be sandboxed separately from the agent entrypoint: the agent runs with normal permissions, but its docker build or docker run invocations are wrapped with a policy that restricts which paths the build context can include and which registries the pull can reach.

Roadmap itemRelationship
Selectable sandbox backendsProcess sandbox is the innermost tier; microVM is the outermost. Both are needed for the strongest isolation model. This item fills the per-operation gap that VM boundaries cannot close.
Network egress policyZerobox implements per-process network policy enforcement at the OS level. Its allow-list mechanism is a concrete implementation path for egress policy inside agent sessions.
Credential proxy (planned)Zerobox’s built-in HTTPS proxy with per-host credential injection is a direct implementation of the credential proxy architecture described in the roadmap overview.
Session snapshot and rollbackZerobox’s snapshot module (Blake3 + Merkle + LZ4) provides per-operation filesystem checkpointing as a lightweight alternative to full container/VM checkpoints.
Rootless DinDBoth are hardening steps that improve the DinD security posture without requiring microVM. Rootless DinD reduces the sidecar’s host privilege; process sandboxing reduces per-operation access inside the container.

gVisor interposes at the syscall layer rather than the filesystem and network layer, providing a user-space kernel that intercepts every system call a process makes. It offers strong process isolation but adds meaningful latency per syscall and does not provide per-process network policy without additional infrastructure. It is more relevant as a container runtime hardening layer than as a per-operation sandboxing mechanism.

WASI (WebAssembly System Interface) provides capability-based isolation for portable Wasm modules. The isolation model is strong and the overhead is low, but it requires code to be compiled to WebAssembly — not applicable to arbitrary shell commands or native build toolchains.

The DinD container already applies a default seccomp profile. Jackin could tighten this by supplying a custom profile tuned to what agent workloads actually need. This is a weaker and more brittle mechanism than process sandboxing: it restricts syscalls globally for the whole container rather than per-operation, and maintaining correct seccomp profiles for diverse agent toolchains is operationally expensive.

  1. Which zerobox integration surface? Shell-out to the zerobox CLI, embed the Rust crate directly, or wait for a more mature API surface before committing to either.
  2. Policy authoring burden. Who specifies which paths and hosts each agent operation may access? Should Jackin derive this from mount configuration automatically, expose it in jackin.role.toml, or leave it to a default-open policy with operator override?
  3. Interaction with Bubblewrap inside the DinD container. DinD currently runs a privileged container. Bubblewrap requires unprivileged user namespaces, which may be restricted by AppArmor on some hosts. Compatibility testing is needed before committing to the Linux mechanism.
  4. Performance at scale. Zerobox reports 10 ms overhead per invocation. An agent making 500 tool calls in a session adds 5 seconds of overhead. At 1000 calls, 10 seconds. Whether this is acceptable depends on the operation mix.
  5. Snapshot policy. Should snapshots be taken before every command, only before commands classified as risky, or only on explicit operator opt-in?