Documentation
¶
Overview ¶
Package sandbox confines a child process's filesystem and network access using OS-level primitives.
Backends:
- native — no-op pass-through. For tests and explicit opt-out.
- bwrap — bubblewrap on Linux. Mounts a fresh root with allowlisted read/write binds, optional --unshare-net.
- sandboxexec — macOS Seatbelt via `sandbox-exec` and a generated .sb profile. Apple has deprecated the CLI but still uses it internally for App Sandbox; no replacement covers ad-hoc CLI sandboxing.
API shape mirrors Anthropic's sandbox-runtime: declare read paths, write paths, network policy, unix-socket allowlist, then call Wrap on a prepared exec.Cmd. The wrap is one-way — the caller drives Start / Wait as usual.
sb, err := sandbox.New() // bwrap on Linux, sandbox-exec on macOS
sb.WithReadPaths("/etc", "/usr").
WithWritePaths(workDir).
WithNetwork(sandbox.NetworkDeny)
cmd := exec.Command("bash", "-c", "...")
if err := sb.Wrap(cmd); err != nil { return err }
return cmd.Run()
Threat model: this package defends against accidental scope creep from tools spawned by an LLM agent — writes outside the workspace, surprise network calls, reads of $HOME secrets. It is NOT a defense against a hostile binary that's actively trying to escape; both bwrap and Seatbelt have known bypasses for unprivileged code that the kernel can't fully isolate (CVE history exists for both).
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNetworkLoopbackUnsupported = fmt.Errorf("sandbox: NetworkLoopback not implemented on Linux bwrap backend (need lo-up helper inside unshared netns); pick NetworkOpen or NetworkDeny, or implement the wrapper — see project_security_e2e.md")
ErrNetworkLoopbackUnsupported is returned by the bwrap backend when NetworkLoopback is requested. macOS sandbox-exec supports it; Linux support is gated on a netns-loopback helper that hasn't been implemented yet. Callers handle this by either falling back to NetworkOpen (less secure but functional) or refusing to start the plugin (most secure but blocks Linux users until the helper lands).
Functions ¶
This section is empty.
Types ¶
type NetworkPolicy ¶
type NetworkPolicy int
NetworkPolicy controls the child process's network access.
const ( // NetworkDeny severs the child's network entirely (Linux: // --unshare-net; macOS: deny network*). Default for new sandboxes. NetworkDeny NetworkPolicy = iota // NetworkOpen leaves networking unrestricted. Explicit opt-in only, // because nothing surfaces "this tool just made an outbound call." NetworkOpen // NetworkLoopback allows local 127.0.0.1 traffic only — the // plugin can bind/connect on loopback (so its gRPC handshake to // the parent works) but EVERY outbound or external connection // is blocked by the OS sandbox. // // This is the secure-by-default policy for codefly plugins: // they need loopback for the agent handshake, and they should // NOT be making outbound calls without an explicit grant. // // Backend status: // macOS sandbox-exec — implemented (rule on localhost ip). // Linux bwrap — NOT implemented; needs `ip link set lo up` // inside the unshared netns (the new netns // has lo DOWN by default). Falls back to // a clear error from Wrap so callers see // the limitation rather than silent // under/over-permissive behavior. NetworkLoopback )
type Sandbox ¶
type Sandbox interface {
// WithReadPaths grants read-only access to absolute paths.
WithReadPaths(paths ...string) Sandbox
// WithWritePaths grants read+write access to absolute paths.
WithWritePaths(paths ...string) Sandbox
// WithNetwork sets the network policy. Default is NetworkDeny.
WithNetwork(policy NetworkPolicy) Sandbox
// WithUnixSockets allows access to specific unix socket paths.
// Distinct from WithReadPaths because socket access on macOS is a
// separate Seatbelt category from filesystem read.
WithUnixSockets(paths ...string) Sandbox
// Wrap takes a prepared exec.Cmd and rewrites it to run inside the
// sandbox. The original cmd.Path / cmd.Args become the wrapped
// command's payload. Stdin/Stdout/Stderr, Env, Dir, and SysProcAttr
// are preserved.
//
// On native (no-op) the cmd is returned unmodified.
//
// Returns an error if the backend is unavailable (bwrap not on
// PATH, sandbox-exec missing) or the policy is malformed.
Wrap(cmd *exec.Cmd) error
// Backend returns the backend in use, for diagnostics.
Backend() Backend
}
Sandbox confines a child process's filesystem and network access.
Path declarations are advisory in the sense that the caller is responsible for declaring everything the child legitimately needs; missing declarations cause runtime denials, not silent breakage. Read paths grant ancestor traversal automatically (bwrap models this; the macOS profile mirrors it).
Sandboxes are single-use. Wrap mutates cmd.Args / cmd.Path — calling Wrap on the same cmd twice will produce nonsense.