procage documentation

How procage cages child processes on macOS and Linux: policies, presets, hard-deny classes, the Seatbelt and Landlock backends, fitting a policy to the host, helpers, lifetime, hygiene, an egress allowlist, async spawning and the threat model.

procage is a Rust library that runs a child process in an OS sandbox. You describe what the child may do in a portable policy; procage lowers it for the system it runs on and spawns the child under it, or refuses and says exactly which part this host cannot enforce.

procage is pre-1.0: the API may change between minor versions.

How it works#

  1. Write a policy with procage::policy (the procage-policy crate), or start from a preset. Everything not granted is denied.
  2. Prepare a cage. Cage::new lowers the policy for this host: a Seatbelt profile on macOS; a Landlock ruleset, seccomp filter and mount plan on Linux. A construct the host cannot enforce is a typed capability gap, never a weaker rule.
  3. Spawn. Cage::spawn forks a child that confines itself with system calls only, then executes the target. If any step fails, the target never runs.
  4. End the run. Dropping the handle kills every process the run started.

Core concepts#

  • Lowering. The policy states intent; the lowering table says, per construct and target, whether it is exact, approximated (only with your consent) or unsupported.
  • Hard-deny tier. Thirteen classes, such as secrets, trust handoff, persistence and container engines, are denied last in every policy and can only be waived by name.
  • Tiers. On Linux, tier T1 adds user namespaces and mounts to Landlock and seccomp; tier T2 has only the latter two. macOS has one mechanism, Seatbelt.
  • Fitting. When a host cannot enforce a policy, Cage::fit relaxes only what you name and says what would lift each relaxation.
  • Violations. An opt-in record of what the sandbox denied, and which rule denied it.
  • Explain and diff. Ask which rule allows or denies reading, writing or executing a path, and what a policy change allows; the kernel checks every answer.
  • Receipts. Every finished run gives a receipt: policy digest, backend and tier, and everything accepted short of the policy.
  • Egress allowlist. With the proxy feature, a run reaches only the hosts an allowlist names (macOS, Linux T1).
  • Async. With the tokio feature, Cage::spawn_async returns an awaitable child and a violation stream.
  • Audits. A protected file with a second name refuses the spawn; the opt-in handoff audit lists what a run left behind.
  • Evidence. Every known escape class has a stable id and a status in the threat model, backed by caged canaries and kernel facts.

All pages

StartGetting startedAdd procage to a Rust project, cage a first command on macOS or Linux, bind a per-spawn grant and read the errors that tell you why a cage was refused.PoliciesPoliciesThe procage policy: a portable, deny-by-default intent layer for files, network, processes, IPC, environment, limits and terminal, and how it is lowered to Seatbelt and Linux plans.PoliciesPresetsprocage's frozen presets (minimal, agent_readonly, agent_workspace, build): what each grants, the base profile and environment they use, and how they behave on Linux tiers.PoliciesHard-deny classesThe thirteen hard-deny classes procage emits last in every policy (secrets, trust handoff, persistence, privilege, process access, terminal injection and more), how to waive one by name, and how Linux tiers enforce them.BackendsmacOS backendHow procage applies Seatbelt on macOS through libsandbox's private interface, without sandbox-exec: path resolution, compiling once, the in-child sequence, what the tests observe and its limits.BackendsLinux backend and tiersHow procage combines Landlock, seccomp and namespaces on Linux into tiers T1 and T2, what each Landlock ABI changes, how to test against older kernels, and its limits.GuidesFitting a policy to the hostCage::fit: when a host cannot enforce part of a policy, relax only what you name, get each relaxation back with what would lift it, and tell your user.GuidesViolations: what the sandbox denied, and whyCageOptions::with_violations: list what the sandbox denied a caged command, with the process, the target and the rule behind each: every denial on macOS, every refused system call on Linux.GuidesExplain and diff: why a path is denied, and what a change allowsCage::explain names the rule that allows or denies reading, writing or executing a path, and the narrowest change that would allow it; explain::diff lists what one policy allows that another does not.GuidesReceipts: evidence of how a run was cagedChild::receipt gives, for every finished run, the policy digest, preset, backend and tier, OS build or kernel, everything accepted short of the policy, the violation summary and the exit: a record a harness can attach to a command's output.GuidesAudits: hard links and what a run left behindBefore every spawn procage refuses a protected, hidden or credential file with a second name outside the protected set; with the handoff audit, Child::audit lists the trust-handoff files, symbolic links and repositories a run created or changed.GuidesAsync: spawning on a tokio runtimeThe tokio feature: Cage::spawn_async returns an awaitable caged child that still ends the whole run, and violations arrive as a stream.GuidesRunning helpers with Cage::execCage::exec and Cage::exec_session turn a small helper program into the caged command, for MCP clients, terminals and async runtimes that start, own and kill the process themselves.GuidesPython: the procage packagepip install procage: presets or JSON policies, a cage, caged runs with pipes, violations and receipts, typed exceptions, and runs that end with their objects.GuidesNode.js: the procage packagenpm install procage: presets or JSON policies, a cage, caged runs with promises, AbortSignal and timeouts, violations and receipts, typed errors that say how to fix a gap.GuidesProxy: network through an allowlistThe proxy feature: a caged child reaches the hosts an allowlist names through a proxy of its run's own, and no other route. One canonical host parser, checked resolution, no allow-all.GuidesLifetime and hygieneHow procage ends a run (sessions, process groups, run markers, double-forked daemons), and the state it keeps from leaking into a child: file descriptors, environment variables, the terminal, temporary files and resource limits.SecurityThreat modelWhat procage defends against (adaptive same-user code in the child), what it trusts, where an OS sandbox stops, and the status of its escape classes. A summary of the canonical THREAT_MODEL.md.SecurityKernel facts and testingHow procage's claims are tested: an escape suite with a caged canary per escape class, a gate on the threat model's catalog, and a kernel-facts suite that re-verifies the OS behaviour procage relies on.HelpFAQCommon questions about procage: production readiness, sandbox-exec, Docker and microVMs, Linux tiers, running inside an AI agent, Windows, and how to report an escape.