Summary / 24. Execution sandbox / Document
Paper 2026-09-06
Shared copy: the operator's name and machine names are replaced by roles. Nothing else is changed.
Rendering…
# Component 24 — The Execution Sandbox ## Containing Arbitrary Generated Code Under a Deterministic Control Plane with Zero Learned Entries --- ### Abstract This paper specifies the twenty-fourth component of the coding harness: the execution sandbox. By component 23 the harness knows, as a declared and evidence-gated state machine, exactly *what order* to run its twenty-two stages in. Component 24 is the boundary that every one of those stages must pass through the moment it stops being a plan and starts being *code that runs*: the candidate patch, the synthesized test, the one-off probe script, the repaired fragment. Its central claim is that execution must be treated as hostile by construction. The sandbox does not ask whether a piece of generated code is safe; it assumes both the code and the agent that generated it are untrusted, and it derives — from the task, not from the model's intentions — the minimum capabilities that task requires, enforcing every filesystem, process, network, device, tool, and secret access through deterministic policy that lives entirely outside the model, tracking the provenance of sensitive data so that individually legitimate operations cannot compose into prohibited flows, running candidate code in ephemeral least-privilege environments that are physically separated from Piper's persistent memory and credentials, and destroying those environments after each candidate or bounded repair episode. The sandbox is the one component of the harness in which the learned column is empty *by construction*: capability derivation, policy enforcement, information-flow and provenance checks, isolation-tier selection, resource envelopes, and side-effect observability are all deterministic software on CPU [D], and the model is not a contributor to the sandbox but the *threat* it contains. We assemble the evidence along five independent boundaries — authority (Progent, MiniScope), data flow (CaMeL, tacit), process (Docker hardening, gVisor), machine (Firecracker), and language/runtime (WebAssembly/WASI) — trace the capability model's lineage from Dennis & Van Horn through seL4, Capsicum, and revocable resource-and-effect capabilities, and close with the honest-measurement machinery (SandboxEval and hostile-fixture CI) that turns "does the box actually hold" from a hope into a check. --- ## 1. Introduction Every component of the harness so far has been, in some sense, an argument that a learned model should do the thinking and deterministic software should do the guaranteeing. Component 24 is where that argument reaches its logical extreme, because the artifact it guards is the only artifact that does not merely *influence* behavior but *executes*: a generated program, running on the same machine Piper lives on, with her memory and her credentials and her network reach somewhere in the same filesystem tree. The entire question of this paper is a single boundary, and the answer it defends is the most conservative one available. **Execution sandboxing should assume both generated code and the agent directing it are untrusted: derive the minimum capabilities required for each task; enforce every filesystem, process, network, device, tool, and secret access through deterministic policy outside the model; track sensitive-data provenance so individually legitimate operations cannot compose into prohibited information flows; execute candidate code in ephemeral least-privilege environments physically separated from Piper's persistent memory and credentials; prefer lightweight verified or capability-oriented runtimes where practical and hardware-backed microVM isolation for arbitrary hostile native execution; deny resources by absence rather than instruction; extract only structured evidence from the sandbox; and destroy the execution environment after each candidate or bounded repair episode.** **The sandbox should remain safe even if Piper deliberately tries to escape it. 'Piper knows she shouldn't' is not part of the threat model.** The second sentence is the human version of the first, and it is the sentence that separates this component from every other. Throughout the harness, the model is a *trusted collaborator* held to account by deterministic gates: the workflow state machine trusts the model to make semantic judgments inside states and trusts the gates to keep those judgments inside bounds. The sandbox cannot afford that trust, because it is not guarding a judgment but a *program*, and a program does not have intentions. The moment the harness's output stops being text the model thought and becomes instructions a CPU will fetch, "the model meant well" stops being a property the system can rely on. The sandbox's design load is therefore not "keep Piper's mistakes contained" but "keep *arbitrary generated code* contained," where "arbitrary" is the operative word. ### 1.1 Why the model's output distribution includes attack payloads The claim that generated code must be treated as arbitrary is not paranoia; it is a reading of the measurement. The relevant findings come from three directions, and they converge on a single point: *the distribution the model samples from contains, at non-negligible mass, outputs that are indistinguishable from attacks.* First, the tool surface is the attack surface. Radosevich and Halloran's *MCP Safety Audit* [1] showed concretely that the Model Context Protocol — the very mechanism by which an agent reaches its tools — "allows major security exploits": a compromised or prompt-injected agent with tool access can exfiltrate data, modify state, and run code, not through any flaw in the model but through the *legitimacy* of the tools it holds. Wang et al.'s MCPTox benchmark [2] sharpened the point from the supply side: real-world MCP servers are themselves poisonable, so the tools an agent calls can be the payload. A sandbox that trusts the agent's tool requests inherits both failures at once. Second, small models are already capable attackers, and capability is rising. Probst, Happe, and Cito [3] measured local, open-weight LLMs on Linux privilege-escalation tasks and found that prior work put small models at only 8–16% success, but that guidance techniques raise two small models (Llama3.1 8B and Qwen2.5 7B) to 67% — matching guided GPT-4o — while Llama3.1 70B reaches 83%, with reflection techniques contributing most and vulnerability *discovery* (not exploitation) the binding constraint. The significance for this component is stark: the payloads are not exotic; they are ordinary privilege-escalation procedures that a model Piper's own harness routinely drives is *already* capable of producing. The sandbox is not defending against a hypothetical. Third, the threat surface is broad and catalogued. Ling, Yu, Chen, and Fang's systematic survey [4] synthesizes 247 papers on LLM-agent security across threat surfaces, attacks, defenses, and evaluation — evidence that the attack space is not a handful of edge cases but a field, and that the sandbox is one of its recognized defense categories. Pirch et al.'s programmatic framing [5] — securing AI agents *like operating systems* — supplies the theoretical posture this paper adopts wholesale: the agent is an untrusted user process, and the sandbox is the kernel that mediates its every reach. Three failure modes deserve naming because each produces a distinct class of payload, and each must be caught by a *mechanism*, not by a plea: - **Injection.** An untrusted instruction embedded in external text — a repository's README, a test fixture's comment, a search result — causes the model to emit behavior the operator never asked for. The model *faithfully* produces an attack because the attack was in its input. Containment must hold regardless of which of the model's inputs were hostile. - **Echo.** The model reproduces, paraphrases, or obeys content it was shown. The payload is not *invented* by the model; it is *replayed*. Again, the model is functioning correctly while emitting hostile code. - **Hallucination.** The model emits a plausible, confident, and *wrong* program — an invented API, a remembered CVE-style exploit, a flag that does not exist. Here the payload is not adversarial at all; it is simply the distribution's own variance, and it is the *most common* case, because every generated program is, until executed, indistinguishable from a hallucination. The three share one property that dictates the architecture: **containment must hold for arbitrary generated text.** The sandbox cannot distinguish "injection," "echo," and "hallucination" from "correct code," and it must not need to. Its guarantee is over the entire output distribution, not over the subset the model meant well. That is what it means for the L column to be empty here: the thing being contained is exactly the thing that, everywhere else in the harness, is the trusted learned entry. ### 1.2 The D/L invariant, at its extreme Every element of this component is classified into one of two columns: **[D]** — deterministic software running on CPU — or **[L]** — a learned model. The structural invariant that governs the entire design is: > **the L column contains at most one entry.** And at this component the invariant is sharpened to its limit. The entire sandbox — capability derivation, policy enforcement, information-flow and provenance checks, isolation-tier selection, resource envelopes, and side-effect observability — is deterministic software on CPU [D]. The model is **not a contributor** to the sandbox; it is the **threat** the sandbox contains. There is no "one learned entry" inside the boundary, because the sandbox's whole job is to be the fixed, non-learning surface against which the learned thing is *tested*. **An empty L column is a permitted, correct state** — and here it is the **only** correct state: a sandbox with any learned entry in its enforcement path has already failed, because it has re-introduced the very entity — a model sampling from a distribution that contains attack payloads — into the one place whose correctness must not be probabilistic. The only learned elements anywhere in the system are **outside** the sandbox boundary: the harness's own model calls, which produce the candidate code the sandbox then *contains*. Inside the boundary there is nothing to learn, and nothing that learns. This is a stronger claim than the sibling components make, and it is the load-bearing one. Component 23 could afford exactly one learned entry — the semantic judgment inside a state — because a state's judgment could be gated by deterministic evidence before and after. The sandbox has no "after" to gate with: once hostile code has executed, the harm is done. The only place the guarantee can live is in the deterministic software that runs *before and during* execution. Hence zero, not one. The rest of the paper makes the argument concretely. §2 draws the five independent boundaries and shows they are layers, not alternatives. §3 specifies the deterministic control plane — capability derivation, policy, provenance, denial-by-absence — and recapitulates the invariant at the architecture level. §4 assembles the isolation tiers as an escalating response to hostility, closed by the CVE that proves single-layer isolation fails. §5 traces the capability model's lineage and makes revocation first-class. §6 is the honest-measurement section: how to know the box actually holds. §7 closes. --- ## 2. The five independent boundaries A sandbox is not one mechanism but a *set* of boundaries, each answering a different question about what a piece of running code can do. The five are frequently conflated into "the sandbox"; keeping them distinct is the first act of design, because each has a different failure mode, a different guarantee, and a different point in the pipeline where it is enforced. They are layered and complementary — no one of them is sufficient, and dropping any one leaves a hole the other four do not cover. ### 2.1 The authority sandbox: what actions and arguments may be requested The outermost boundary constrains not what a process can *touch* but what it can *ask for*. An agent with a tool surface — read file, run command, push commit, send message — is dangerous before any bytes are written, because the *request itself* carries authority. Two systems specify this boundary. **Progent** — *Securing AI Agents with Privilege Control*, by Shi, He, Wang, Li, Wu, Guo, and Song [6] (arXiv:2504.11703) — gives the agent a symbolic policy language over **tool names and arguments**, evaluated by a policy engine outside the model. Its primitives are two, and they must be named precisely because they are the teeth of the boundary: **ALLOW** and **FORBID** rules (the rule's "Effect" field is `allow` or `forbid`), plus a **Fallback action** with three forms — terminate, notify the user, or return an error message (the default). There is no "substitute" and no "deny" keyword; the vocabulary is allow/forbid with a fallback when the policy cannot decide. The mechanism is monotonic confinement solved by SMT: the policy engine narrows or expands the argument space symbolically, so the allowed region is a *provable* region, not a heuristic one. On AgentDojo its enforcement cuts the attack success rate (ASR) from 39.9% to 1.0% and the attack success with jailbreak (ASB) from 70.3% to 3.9%. Progent answers the question "may the agent even *ask* for this tool with these arguments," and it answers it in software. **MiniScope** — *A Least Privilege Framework for Authorizing Tool Calling Agents*, by Zhu, Tseng, Vernik, Huang, Patil, Fang, and Popa [7] (arXiv:2512.11147, a preprint with no peer-reviewed venue as of this writing) — solves the harder upstream problem: *what is the least privilege this task actually needs?* It takes a mobile-OS-style authorization model and **reconstructs permission hierarchies** from the tool surface, so each task is granted only the permissions its declared tools require, and the model cannot request beyond them. Across 10 real applications it incurs only **1–6% latency overhead**, which is the number that matters for this boundary: least privilege is affordable enough to be default, not a luxury. Where Progent is the *enforcer*, MiniScope is the *deriver* — it produces the minimum capability set that Progent (or the control plane of §3) then holds the agent to. The authority boundary is what makes "trusted agent, untrusted inputs" the *wrong* frame. Injection and echo payloads arrive through the tool request itself; Progent and MiniScope treat the request as data to be authorized, never as an intention to be honored. ### 2.2 The data-flow sandbox: where sensitive information may flow The authority boundary controls what the agent may *do*; the data-flow boundary controls what may *flow through* it. A program that is allowed to read a file and allowed to make a network call is not dangerous until it does both with the same data — the classic confused-deputy and exfiltration pattern. Authority-per-action is blind to this, because each action is individually legitimate; only *provenance tracking* can see the composition. **CaMeL** — *Defeating Prompt Injections by Design*, by Debenedetti, Shumailov, Fan, Hayes, Carlini, Fabian, Kern, Shi, Terzis, and Tramèr [8] (arXiv:2503.18813, IEEE SaTML 2026) — is the strongest statement of the principle: it tracks **capabilities and data provenance** so that a value tainted by an untrusted source cannot be exfiltrated over an unauthorized flow, and it does so *by design* rather than by detection. Its architecture is a **privileged planner** plus a **policy-enforcing interpreter**: the planner (the part that talks to the model) and the interpreter (the part that executes) are separated, and the interpreter refuses any data flow the provenance rules forbid. On AgentDojo it solves **77%** of tasks with provable security, against **84%** for the undefended baseline. The point is not the number; it is the word *provable*: CaMeL's guarantee does not depend on the model noticing anything. **tacit** — *Tracking Capabilities for Safer Agents* (arXiv title) / *Securing Agents With Tracked Capabilities* (ACM CAIS '26 published title), by Odersky, Zhao, Xu, Bračevac, and Pham [9] (arXiv:2603.00991) — pushes the guarantee into the type system. It is a Scala 3 library that uses the language's **capture checking** to track, at compile time, which capabilities a function may exercise, and it introduces a **`Classified[T]`** type whose `map` operation accepts **only pure functions** — functions with an empty capture set — so that a sensitive value can be transformed but never *released*. Across **131 trials** (120 prompt-injection tasks plus 11 deliberately malicious tasks), tacit achieves **100% security** in classified mode for both Claude Sonnet 4.6 and MiniMax M2.5 (utility 99.2% and 90.0% respectively); in unclassified mode security degrades to 98.5% and 91.6%. The number to notice is the *mechanism*: the capture checker is a compiler, and the compiler is the part of the toolchain that cannot be prompt-injected. CaMeL and tacit are the same idea at two levels — runtime provenance and compile-time capture — and both answer the question "where may sensitive information flow" with a *deterministic* answer. That determinism is exactly why they belong inside the control plane of §3 rather than in the model's conscience. ### 2.3 The process sandbox: what the process can touch Below the request and the flow sits the *process* — the actual Unix process that will execute the generated code. This boundary is the classical one: limit what the process can see and touch through the operating system's own facilities. It is enforced by Linux mechanisms (capabilities, seccomp filtering, user namespaces, a read-only root filesystem) and, for stronger isolation, by a userspace kernel. These are **practitioner mechanisms, not papers** — seccomp and Landlock are Linux kernel features, Docker hardening is an OCI configuration discipline, and gVisor is open-source software — so they are described here as engineering context and cited only through the *research* that measured them (§4). The one fact to carry forward now is the posture: **deny by default.** The process starts with nothing and receives only what the task's derived capability set (§3.1) grants it — no ambient filesystem, no ambient network, no device nodes, no secrets in the environment. ### 2.4 The machine sandbox: hardware-backed isolation When the generated code is *arbitrarily hostile native code* — a fork-bomb, a kernel-exploit attempt, a rootkit — no amount of in-process filtering is a real guarantee, because the process shares a kernel with Piper. The machine boundary gives the hostile code its own *virtual machine*, backed by the hypervisor, so that "escape the process" requires "escape the hypervisor," a categorically harder problem. **Firecracker** — the AWS microVM manager, by Agache, Brooker, Florescu, Iordache, Liguori, Neugebauer, Piwonka, and Popa [11] (USENIX NSDI 2020) — is the canonical instance, and its numbers are the reason microVMs are practical here at all: **~50K lines of Rust** (roughly **96% fewer than QEMU**), **less than 5 MiB** of memory overhead per microVM, boot in **as little as 125 ms**, and **up to 150 microVMs per second per host**. It powers AWS Lambda and Fargate, which is the strongest existence proof available that per-task virtual machines are *operational*, not aspirational. A machine boundary is the fallback for the cases the process boundary cannot name. ### 2.5 The language/runtime sandbox: verified and capability-oriented execution The innermost boundary constrains the *language* the code is written in. If generated code is compiled to a sandboxed intermediate representation whose semantics are small enough to verify, then "what can this code do" becomes a property of the compiler rather than of the environment. **WebAssembly and WASI** are the practical instance, and Bosamiya, Lim, and Parno's *Provably-Safe Multilingual Software Sandboxing using WebAssembly* [12] (USENIX Security 2022, Distinguished Paper Award) is the research that makes the "provably" honest: **vWasm** is an F\*-verified WebAssembly-to-native compiler, and **rWasm** is a safe-Rust runtime (`#![forbid(unsafe)]`, `#![no_std]`). Its headline number is precise and worth quoting exactly: the sandboxing pass itself costs **only ~0.2%** runtime — "the run time is marginally affected (by only 0.2%)" when the sandboxing pass is disabled — meaning the near-entirety of vWasm's slowdown lives in the *unverified* optimization portion, not in the part that guarantees memory safety. WASI completes the picture on the capability side: its **import allowlisting** means a module can reach *only* the host capabilities it was explicitly given, which is the capability model of §5 applied at the module boundary. ### 2.6 Layered, complementary, not alternatives The five boundaries are not five candidate sandboxes from which to choose one. They are five questions, and a hostile program must lose at every one of them: - The **authority** boundary asks: *may the agent request this action with these arguments?* — and answers before anything runs. - The **data-flow** boundary asks: *may this value, with this provenance, flow to this sink?* — and answers during execution. - The **process** boundary asks: *may this process touch this file, socket, or device?* — and answers in the kernel. - The **machine** boundary asks: *may this code share a kernel with Piper at all?* — and answers in the hypervisor. - The **runtime** boundary asks: *is this program's semantics small enough to verify?* — and answers in the compiler. Each is enforced by a different piece of the stack, so no single compromise — a prompt injection, a confused deputy, a kernel bug, a hypervisor bug, a compiler bug — defeats the whole. The rest of this paper assigns each boundary its machinery: §3 owns the authority and data-flow boundaries (the deterministic control plane), §4 owns the process and machine boundaries (the isolation tiers), and §5 owns the runtime boundary's conceptual foundation (the capability model). --- ## 3. The deterministic control plane (D) The control plane is the software that decides, before and during execution, what the running code is *allowed to do* — and it is, by construction, entirely outside the model. This section specifies it in four parts: capability derivation (what the task needs), policy enforcement (what the request may be), information-flow and provenance (what the data may do), and denial-by-absence (what is never present to be asked for). Recapitulating the invariant at the architecture level, because this is the section it governs: > **the L column contains at most one entry.** The entire control plane — capability derivation, the policy engine, the information-flow and provenance checks, the isolation-tier selector, the resource envelopes, and side-effect observability — is deterministic software on CPU [D], holding **zero learned entries by construction**. The model is **not a contributor** to this plane; it is the **threat** the plane contains. **An empty L column is a permitted, correct state** — and here it is the **only** correct state: a control plane with any learned entry in its enforcement path has already failed, because it has put a sample from a distribution that contains attack payloads in charge of deciding what the payload may do. The only learned elements in the system are **outside** the boundary — the harness's own model calls, which emit the candidate code — and **inside** the boundary there is nothing to learn. ### 3.1 Capability derivation: MiniScope least privilege The control plane's first act is to *derive* the minimum capability set for a task, because "minimum" cannot be assumed; it must be computed. **MiniScope** [7] is the prior that makes this concrete: given a tool surface, it reconstructs the permission hierarchy and grants a task exactly the permissions its declared tools require — no more — with **1–6% latency overhead** across 10 applications, which is the number that licenses treating least privilege as the *default* rather than an opt-in. In the harness's terms, capability derivation takes the workflow state's declared task (§23's state schema) and produces a **capability manifest**: the set of filesystem paths, network endpoints, devices, tools, and secrets that the candidate code for *this* task may touch. Anything not in the manifest is not merely "blocked" — it is *absent* (§3.4). The derivation is a pure function of the task, not of the model, so the same task always derives the same manifest, and the manifest can be audited, diffed, and regression-tested like any other artifact. ### 3.2 The policy engine: Progent ALLOW/FORBID + Fallback Given a manifest, the policy engine holds every request to it. **Progent** [6] supplies the enforcement discipline: symbolic rules over **tool names and arguments**, with exactly two rule effects — **ALLOW** and **FORBID** — and a **Fallback action** (terminate, notify the user, or return an error message, the last being the default) for requests the rules do not decide. The word to insist on is *symbolic*: Progent's SMT-solved monotonic narrowing and expansion means the allowed region is a *computed* region, and a request either lies inside it (allowed) or outside it (forbidden or fallback) — never in an interpretive gray zone the model resolves. Mapped onto this harness, the policy engine is the deterministic gate that every tool invocation and every filesystem/network/device access passes through, comparing the requested operation and arguments against the capability manifest. Its provenance is the point: the engine runs *outside* the model, on the same authority that evaluates the workflow's gate predicates (§23), and a forbidden request is not "helpfully reinterpreted," not "routed to a safer tool," not "asked about" — it is refused, and the refusal is an observable event the workflow can react to. ### 3.3 Information-flow and provenance: CaMeL and tacit The authority boundary (§3.2) authorizes actions; the data-flow boundary makes sure authorized actions cannot *compose* into prohibited flows. This is the layer that catches the classic exfiltration — read a secret, write it to the network — where each step is individually legitimate. **CaMeL** [8] provides the runtime form: a **privileged planner** separated from a **policy-enforcing interpreter**, with **capability-tagged data flow** so that a value whose provenance is a sensitive source can never reach an unauthorized sink. The interpreter, not the model, decides each flow, which is why CaMeL's guarantee is *provable* (77% of AgentDojo solved vs 84% undefended) rather than statistical. **tacit** [9] provides the compile-time form: **Scala 3 capture checking** tracks which capabilities each function may exercise, and a **`Classified[T]`** type whose `map` accepts **only pure functions** (empty capture set) means a sensitive value can be transformed in place but never released — **100% security across 131 trials** in classified mode for both Sonnet 4.6 and MiniMax M2.5. The two are the same invariant at two levels of the stack: *a tainted or sensitive value may be processed, but its flow out of the boundary is a deterministic decision, never the model's.* In the harness, provenance tags ride on every value the sandbox produces and consumes; the flow checker is software on CPU [D], and an attempted prohibited flow is an event, not a negotiation. ### 3.4 Denial by absence The last element is the one that closes the loop the other three leave open: a resource that is not *denied* but *absent* cannot be reached by any sequence of authorized actions, because there is no handle to it at all. **Deny resources by absence rather than instruction.** A secret that is never mounted into the sandbox cannot be read, however clever the request; a network namespace with no routes cannot egress, however plausible the code; a device node that does not exist cannot be opened. This is the difference between a *filter* (which sits in the path and can be bypassed or misconfigured) and a *construction* (which never puts the resource in the environment to begin with). The capability manifest of §3.1 is therefore not a blacklist to be enforced so much as a *build recipe*: the sandbox is constructed with exactly the resources the manifest names, and everything else is simply not there. This is the mechanism that makes the sandbox's guarantee *structural* rather than *behavioral* — and it is the reason the D/L invariant can be stated as zero rather than one: absence is enforced by what was built, not by anything that runs. --- ## 4. The isolation tiers The control plane decides what is *allowed*; the isolation tiers decide what is *physically reachable*. They are an escalating ladder, each rung trading overhead for a categorically stronger guarantee, and the sandbox climbs it according to how hostile the code is assumed to be. The ladder is also the answer to a specific historical failure that proves single-layer isolation is insufficient. ### 4.1 Hardened containers: the cheap first rung The first rung is a standard container with the operating system's own defenses turned up to maximum: **capability dropping** (start with none, add back only what the task needs), **seccomp** filtering (restrict the syscall surface), **user namespaces** (map the container's root to an unprivileged host user), and a **read-only root filesystem**. These are **practitioner mechanisms, not papers** — seccomp is a Linux kernel feature (2005, with the BPF-filtered form in 2012), Landlock is a kernel feature merged in Linux 5.13 (2021), and the discipline itself is Docker/OCI configuration — so they appear here as engineering context and nowhere in the reference list as citable research. Their value is cost: a hardened container boots in milliseconds and carries the lowest overhead of any tier. Their limit is the one this section's failure case makes vivid: they all *share the host kernel*, so a kernel-level escape is an escape from all of them at once. ### 4.2 gVisor: a userspace kernel, measured The second rung addresses the shared-kernel problem without giving up container speed, by moving the kernel boundary into userspace. gVisor is Google's **application kernel** — a userspace kernel (with the `runsc` OCI runtime) that intercepts the process's syscalls and re-implements them against a small, constrained host surface, so a process running under gVisor talks to the *userspace* kernel, not the host kernel, for most operations. gVisor is **software, not a paper** — it is open-source, and the "~200 syscalls" figure that circulates for it is wrong. The citable research is Young, Zhu, Caraza-Harter, Arpaci-Dusseau, and Arpaci-Dusseau, *The True Cost of Containing: A gVisor Case Study* [10], **USENIX HotCloud '19** (UW-Madison, not Google, and not NSDI 2020). Its measured numbers are the ones this paper relies on: gVisor exposes **~53 allowlisted syscalls** (no host networking) or **~68** (with host networking), against **~306 for LXC** and **~36 for Firecracker** — deny-by-default with a small allowlisted surface, in the right direction but at ~53–68, not ~200. The cost is structural to the userspace-kernel design: simple syscalls run **~2.2× slower** than a standard container (about 2.8× vs native in the fastest configuration), but syscall-heavy workloads degrade far worse — open/close on an external tmpfs reaches **~216×**. The lesson for the harness is a tradeoff, not a verdict: gVisor buys a much smaller, constrained syscall surface at a steep per-syscall price, so it is the right rung when the code is untrusted *enough* to justify a userspace kernel but *not* hostile enough to justify a virtual machine. ### 4.3 Firecracker: the machine boundary The third rung is the one that stops assuming good faith in the *kernel*. **Firecracker** [11] (Agache et al., NSDI 2020) is the AWS microVM manager, and its numbers make per-task virtual machines the practical default rather than a luxury: **~50K lines of Rust** (~96% fewer than QEMU), **less than 5 MiB** memory overhead per microVM, boot in **as little as 125 ms**, **up to 150 microVMs per second per host**, and it is the engine under **Lambda and Fargate**. A hostile native program in a Firecracker microVM shares nothing with Piper but the hypervisor: its filesystem, network, devices, and secrets are all whatever the harness constructed for it (§3.4), and "escape the sandbox" now means "escape KVM," a categorically harder and better-audited target. This is the rung the thesis reserves for "arbitrary hostile native execution": when the code is assumed hostile — as this component assumes by default — the machine boundary is the one that makes the assumption *safe* to hold. ### 4.4 Wasm/WASI: the verified runtime boundary The fourth rung inverts the question. Instead of giving hostile code a weaker environment, it gives it a *safer language*: compile the generated code to WebAssembly and constrain it with WASI, so that "what can this code do" is a property of a small, verifiable semantics rather than of a large, shared kernel. **Bosamiya, Lim, and Parno** [12] (USENIX Security 2022, **Distinguished Paper Award**, plus the Internet Defense Prize, tied 2nd) provide the proof that the guarantee is real: **vWasm** (an F\*-verified Wasm-to-native compiler) and **rWasm** (a safe-Rust runtime) — and the sandboxing pass itself costs **only ~0.2%** runtime, with the slowdown living almost entirely in the unverified optimization portion. WASI's **import allowlisting** supplies the capability side: a module reaches only the host capabilities it was explicitly handed, which is the capability model of §5 applied at the module boundary. This is the thesis's "lightweight verified or capability-oriented runtime": where the generated code's task fits inside WebAssembly's model, the sandbox can offer a *verified* guarantee at near-native cost — a strictly better deal than any filter, and the reason the ladder *descends* back down in cost at its top rung. ### 4.5 Why single-layer isolation fails: CVE-2019-5736 The ladder exists because of a specific, documented failure of believing one layer was enough. **CVE-2019-5736** is a runc container-escape vulnerability — cited here as a **CVE/advisory, not a paper** — in which a process *inside* a container, with root-in-container, could overwrite the host's `runc` binary via `/proc/self/exe` file-descriptor mishandling and achieve host root code execution. It affected runc through 1.0-rc6 (Docker < 18.09.2, containerd, CRI-O), carried a CVSS score around 8.6 (High), and the same flaw existed in LXC. The lesson is not "containers are unsafe"; it is that **every layer assumes the one beneath it**, and a single layer is a single point of assumption. The rung's defenses — capability dropping, seccomp, user namespaces — all shared the host kernel and the `runc` entry path, so one kernel-adjacent bug defeated the whole rung. A machine boundary (a microVM whose kernel is its own) would have contained the escape at the hypervisor; a runtime boundary (Wasm, where `/proc/self/exe` does not exist) would have made the attack unexpressible. The five boundaries of §2 and the four rungs of this section are the same conclusion stated twice: **isolation must be layered, because each layer fails, and the failure of any one must not be the failure of the whole.** --- ## 5. The capability model's lineage The runtime boundary of §4.4 and the provenance machinery of §3.3 both rest on a single idea that predates every component of this harness by six decades: the **capability** — a token that *is* the authority to use a resource, rather than a name that must be checked against a separate access-control list. This section places the sandbox in that lineage, because the capability model is what makes "deny by absence" and "derive least privilege" and "revoke mid-session" into *one* coherent story rather than three ad-hoc mechanisms. ### 5.1 Dennis & Van Horn: the object, the capability, the domain The foundation is Dennis and Van Horn, *Programming Semantics for Multiprogrammed Computations* [13], *Communications of the ACM*, Vol. 9, No. 3, pp. 143–155, 1966, DOI 10.1145/365230.365252. It is the paper that defined, in a single formal setting, the **object**, the **capability**, and the **domain** — and, decisively for this component, **confinement** and **revocation**. Confinement is the property the sandbox needs *named*: a confined computation can reach only what its capabilities name, so an untrusted program's reach is exactly the set of tokens it was handed, and nothing else. Revocation is the property §5.3 returns to: a capability is a thing that can be *taken back*. Every mechanism in this paper — the capability manifest of §3.1, the provenance tags of §3.3, the WASI imports of §4.4, the revocable handles of §5.3 — is an elaboration of this 1966 definition. ### 5.2 The descendants: seL4, Capsicum, WASI The lineage from Dennis & Van Horn to the present runs through three descendants, each of which adds the property a modern sandbox needs: - **seL4** — Klein, Elphinstone, Heiser, Andronick, Cock, Derrin, Elkaduwe, Engelhardt, Kolanski, Norrish, Sewell, Tuch, and Winwood, *seL4: Formal Verification of an OS Kernel* [14] (ACM SOSP '09, DOI 10.1145/1629575.1629596) — is the capability model pushed to its strongest conclusion: a microkernel whose capability-based isolation is **formally verified**, so the confinement guarantee is a theorem about the kernel, not a hope about the kernel's implementation. It is the reason a sandbox can *aspire* to a proof rather than a test. - **Capsicum** — Watson, Anderson, Laurie, and Kennaway, *Capsicum: practical capabilities for UNIX* [15] (19th USENIX Security Symposium, USENIX Security '10; note the lowercase "practical") — is the capability model translated into the operating system everyone actually runs: it adds **capability mode** and **capability-based file descriptors** to FreeBSD (and informs similar work elsewhere), so a process can be *placed into* a mode where the only way to touch anything is through a capability handle it already holds. Capsicum is the bridge from "capabilities are a research OS idea" to "capabilities are a syscall away." - **WASI import allowlisting** — the WebAssembly System Interface — applies the same move at the module boundary, as described in §4.4: a module's entire reach is its explicitly-declared imports, which is a capability set in everything but name. (WASI is a specification, not a paper; its capability semantics are what Bosamiya, Lim, and Parno [12] make provable on the runtime side.) The older roots deserve one more nod for completeness. **Henry M. Levy's *Capability-Based Computer Systems* [16] (Digital Press, 1984)** is the book-length survey of the capability machines — the 1966–1984 lineage of hardware and OS designs that tried to make capabilities the *native* addressing mode — and it is cited as a **book, not a paper**. And **Janus** — Goldberg, Wagner, Thomas, and Brewer, *A Secure Environment for Untrusted Helper Applications: Confining the Wily Hacker* [17] (6th USENIX Security Symposium, July 1996) — is the historical bridge in the other direction: a sandbox that confined untrusted helper applications by **ptrace**-based syscall interposition (note: **ptrace, not BPF** — BPF-based sandboxing arrived later, around seccomp-bpf in 2012, and conflating the two misdescribes Janus's mechanism). Janus is the ancestor of the *filter* approach; the capability lineage is the ancestor of the *construction* approach (§3.4), and this paper deliberately favors the latter. ### 5.3 Revocation as first class: Lingering Authority The capability model's classic weakness is **lingering authority**: a capability granted for one episode that outlives the episode and can be replayed later. The sandbox's ephemerality requirement — *destroy the execution environment after each candidate or bounded repair episode* — is precisely a demand that no authority linger. **Lingering Authority: Revocable Resource-and-Effect Capabilities for Coding Agents**, by Santos-Grueiro [18] (arXiv:2606.22504, June 2026, a single-author preprint with no peer-reviewed venue as of this writing; the system is named **PORTICO**), makes revocation a *first-class* capability property rather than an afterthought: capabilities carry **resource and effect scopes**, and they are **revocable mid-session** — episode-bound capability handles whose closure revokes them, so a stale handle replayed after the episode is rejected, not honored. Two flags attach to this citation and must be stated honestly. First, the paper is fresh (June 2026), single-author, and unrefereed; it is cited for its *mechanism* (resource + effect scopes, mid-session revocation, stale-replay rejection), which is confirmed from the abstract, and it should be re-checked against any peer-reviewed version before it is load-bearing in production. Second, the claim sometimes attached to it — that it is "grounded in Saltzer & Schroeder" — is **not in the abstract**, and this paper does **not** assert that grounding; it is flagged as unverified until the body is checked. The revocation *property itself*, however, is not in doubt, and it is exactly the property the thesis's "destroy the environment" clause needs: authority is not merely narrowed but *expires*, and a capability that has been revoked is as absent as a resource that was never mounted (§3.4). Revocation-by-expiry is denial-by-absence applied to *time*. --- ## 6. Honest measurement: does the box actually hold? The first five sections specified a sandbox; this section asks the question that separates a specification from a *guarantee*: how do we know it holds? A sandbox whose confinement is asserted but never tested is a hope, and a hope is not a component. The measurement machinery has three parts, and all three are deterministic software on CPU [D] — the sandbox's own verification is, like the sandbox, outside the model. ### 6.1 SandboxEval: the adversarial suite The direct answer to "does the box hold" is an **adversarial test suite** that tries to break it and fails. **SandboxEval: Towards Securing Test Environment for Untrusted Code**, by Rabin, Hostetler, McGregor, Weir, and Judd [19] (arXiv:2504.00018), is the prior that frames this precisely, and it must be cited with its caveat attached: its arXiv comments state **"preliminary version, working paper"**, so it is not a peer-reviewed venue — it is a *working* framework, not a finished one. Its substance is still exactly the right shape: **51 properties** across the categories that matter — **sensitive-information exposure**, **filesystem manipulation/escape**, **external network communication**, **resource exhaustion** (CPU/disk/network), and **privilege escalation**. That list is, in effect, the five boundaries of §2 restated as attack families: the authority boundary tested by privilege escalation, the data-flow boundary tested by sensitive-information exposure, the process and machine boundaries tested by filesystem escape and network egress, and every boundary tested by resource exhaustion. The harness adopts SandboxEval's *shape* — an enumerated property list, each property a concrete "the sandbox must prevent X" — and runs it as the sandbox's own regression suite, so that a change to the sandbox (a new rung, a widened manifest, a relaxed seccomp profile) must *re-pass every property* or fail CI. ### 6.2 Hostile-fixture CI: the payloads we actually generate SandboxEval-style properties are the *specification*; the second part is the *evidence from the field*. The harness runs, as a standing CI job, a corpus of **hostile fixtures** — the concrete payloads a coding agent actually produces: **fork-bombs** (resource exhaustion), **egress probes** (network escape attempts), **secret-grepping payloads** (attempts to read credentials and exfiltrate them), and injected-instruction fixtures (a README or comment carrying an embedded "run this" instruction, exercising the injection/echo/hallucination triple of §1.1). The fixtures are the *positive* controls: each is a program that *should* be contained, and the CI asserts — deterministically — that each is. This is the honest-measurement answer to the attack-side literature of §1.1 [1, 2, 3]: those papers document that agents *do* produce hostile code; the hostile-fixture corpus documents that *this* sandbox contains it. The two must be kept in correspondence, not comfort. ### 6.3 The boundary audited like code The third part treats the sandbox itself as a piece of code that must be *audited*, not trusted. Concretely: the sandbox's CVE exposure is tracked the way a production service's would be — the **CVE-2019-5736** runc escape of §4.5 is the standing example of the failure class this audit exists to catch, and it is cited here as an **advisory, not a paper**. The audit asks, continuously: which runtimes and kernels does the sandbox depend on, what are their open advisories, and does the current tier selection expose Piper to any of them? The loop is boring and mechanical, and that is the point — "isolation is layered" is only true if the layers are *kept* layered, and a single unpatched runc in the chain silently un-layers them. ### 6.4 Two practitioner caveats, stated so they are not mistaken for citations Two adjacent lines of work are worth naming so their status is clear. **AutoSec-Agent** — Amin, Mehmood, Kamarulzaman, Costanzo, Alsubaei, and Alshehri, *AutoSec-Agent: a fully autonomous and ethical multi-agent framework for scalable penetration testing using large language models* [20], *Complex & Intelligent Systems* (Springer), DOI 10.1007/s40747-026-02447-5 — is a *real, peer-reviewed paper* (received 14 Apr 2026, accepted 16 Jul 2026, published 30 Jul 2026; currently early-access/ahead-of-print) whose abstract reports that its containerized, hardened sandbox **decreases unsafe command generation by 87%** and **decreases hallucination rates by 62%**. It is cited here as peer-reviewed evidence that a containerized sandbox measurably reduces unsafe output — and its numbers are from the abstract, confirmed, not paraphrased. By contrast, **Jiang's *Runtime Protection Practice for LLM Agent Security: An On-Demand Behavioral Sandbox Approach* [21]** (ISAEECE 2026, IEEE, pp. 587–590, DOI 10.1109/isaeece70502.2026.11635191) is a *real but low-tier* IEEE conference short paper whose headline numbers — a claimed 0.0% execution-hallucination rate, 660 ms median latency, and 200 LITMUS/AgentDojo tasks — **could not be independently confirmed from a primary source** (Crossref carries no abstract and the IEEE page is not machine-accessible), so they are **flagged as unverified** and deliberately *not* relied upon here. The asymmetry is the discipline itself: one peer-reviewed, abstract-confirmed source is worth ten unverifiable secondary summaries, and the sandbox's evidence base is built accordingly. Finally, the extraction discipline closes the loop on the thesis's "extract only structured evidence": the sandbox's output is not its logs in prose, not the model's narration of what happened, but a **structured evidence record** — exit code, stdout/stderr bounded and hashed, resource counters, provenance-tagged files touched, network flows denied — and that record is the only thing that crosses the boundary back into the harness. **GoEX** — Patil, Zhang, Fang, Noppapon C., Huang, Hao, Casado, Gonzalez, Popa, and Stoica, *GoEX: Perspectives and Designs Towards a Runtime for Autonomous LLM Applications* [22] (arXiv:2404.06921) — supplies the two properties the harness borrows: **undo semantics** and **post-facto validation with human oversight**, i.e., a runtime that makes actions reversible and checkable *after* they happen. The sandbox's "destroy the environment" is the strongest form of both: undo by annihilation, and the evidence record is the only surviving residue by which any action can be post-facto validated. --- ## 7. Conclusion The coding harness's twenty-fourth component is the boundary every other component's output must cross before it becomes a *running program* — and the argument of this paper is that the boundary must be built to contain arbitrary generated code, not merely mistaken code. **Execution sandboxing should assume both generated code and the agent directing it are untrusted: derive the minimum capabilities required for each task; enforce every filesystem, process, network, device, tool, and secret access through deterministic policy outside the model; track sensitive-data provenance so individually legitimate operations cannot compose into prohibited information flows; execute candidate code in ephemeral least-privilege environments physically separated from Piper's persistent memory and credentials; prefer lightweight verified or capability-oriented runtimes where practical and hardware-backed microVM isolation for arbitrary hostile native execution; deny resources by absence rather than instruction; extract only structured evidence from the sandbox; and destroy the execution environment after each candidate or bounded repair episode.** **The sandbox should remain safe even if Piper deliberately tries to escape it. 'Piper knows she shouldn't' is not part of the threat model.** The design reduces to one structural invariant, stated once more, in its strongest form: > **the L column contains at most one entry.** The entire sandbox — capability derivation, policy enforcement, information-flow and provenance checks, isolation-tier selection, resource envelopes, and side-effect observability — is deterministic software on CPU [D], with **zero learned entries by construction**. The model is not a contributor to the sandbox; it is the threat the sandbox contains. And **an empty L column is a permitted, correct state** — here it is the **only** correct state: a sandbox with any learned entry in its enforcement path has already failed, because it has put the very entity whose output distribution includes attack payloads in charge of containing those payloads. The only learned elements in the system are outside the boundary — the harness's own model calls, which emit the candidate code — and inside the boundary there is nothing to learn. Progent and MiniScope put the authority boundary in deterministic software [6, 7]; CaMeL and tacit put the data-flow boundary in a policy-enforcing interpreter and a capture-checking compiler [8, 9]; the isolation tiers climb from hardened containers through a measured userspace kernel [10] to a hypervisor-backed microVM [11] and a formally verified runtime [12], closed by the runc escape [CVE-2019-5736] that proves one layer is never enough; Dennis & Van Horn gave the capability model its confinement and revocation [13], and seL4, Capsicum, and Lingering Authority carried it to a verified kernel, a practical syscall, and a revocable, effect-scoped handle [14, 15, 18]; and SandboxEval plus hostile-fixture CI turn "does the box hold" from a hope into a regression suite [19]. The sandbox is the component where the harness's deepest principle is stated with the least hedging: the learned thing is what runs *inside* the boundary, and the thing that keeps it there is the part that cannot be learned, cannot be prompted, and cannot be escaped — because it was never asked to think, only to hold. --- ## References [1] Brandon Radosevich and John Halloran. "MCP Safety Audit: LLMs with the Model Context Protocol Allow Major Security Exploits." arXiv:2504.03767, 2025. [2] Zhiqiang Wang, Yichao Gao, Yanting Wang, Suyuan Liu, Haifeng Sun, Haoran Cheng, Guanquan Shi, Haohua Du, and Xiangyang Li. "MCPTox: A Benchmark for Tool Poisoning Attack on Real-World MCP Servers." arXiv:2508.14925, 2025. [3] Benjamin Probst, Andreas Happe, and Jürgen Cito. "Enhancing Linux Privilege Escalation Attack Capabilities of Local LLM Agents." In *Proceedings of the RAISE Workshop* (accepted), 2026. arXiv:2604.27143. [4] Yuchen Ling, Shengcheng Yu, Zhenyu Chen, and Chunrong Fang. "Toward Secure LLM Agents: Threat Surfaces, Attacks, Defenses, and Evaluation." arXiv:2606.10749, 2026. [5] Lukas Pirch, Micha Horlboge, Patrick Großmann, Syeda Mahnur Asif, Klim Kireev, Thorsten Holz, and Konrad Rieck. "Toward Securing AI Agents Like Operating Systems." arXiv:2605.14932, 2026. [6] Tianneng Shi, Jingxuan He, Zhun Wang, Hongwei Li, Linyu Wu, Wenbo Guo, and Dawn Song. "Progent: Securing AI Agents with Privilege Control." arXiv:2504.11703, 2025 (v3 May 2026). [7] Jinhao Zhu, Kevin Tseng, Gil Vernik, Xiao Huang, Shishir G. Patil, Vivian Fang, and Raluca Ada Popa. "MiniScope: A Least Privilege Framework for Authorizing Tool Calling Agents." arXiv:2512.11147, 2025. (CoRR preprint; no peer-reviewed venue as of this writing.) [8] Edoardo Debenedetti, Ilia Shumailov, Tianqi Fan, Jamie Hayes, Nicholas Carlini, Daniel Fabian, Christoph Kern, Chongyang Shi, Andreas Terzis, and Florian Tramèr. "Defeating Prompt Injections by Design." In *IEEE Conference on Secure and Trustworthy Machine Learning* (SaTML 2026). arXiv:2503.18813. [9] Martin Odersky, Yaoyu Zhao, Yichen Xu, Oliver Bračevac, and Cao Nguyen Pham. "Securing Agents With Tracked Capabilities." In *ACM Conference on AI Systems* (CAIS 2026). arXiv:2603.00991. (arXiv title: "Tracking Capabilities for Safer Agents.") [10] Ethan G. Young, Pengfei Zhu, Tyler Caraza-Harter, Andrea C. Arpaci-Dusseau, and Remzi H. Arpaci-Dusseau. "The True Cost of Containing: A gVisor Case Study." In *Proceedings of the 11th USENIX Workshop on Hot Topics in Cloud Computing* (HotCloud '19), 2019. [11] Alexandru Agache, Marc Brooker, Andreea Florescu, Alexandra Iordache, Anthony Liguori, Rolf Neugebauer, Phil Piwonka, and Diana-Maria Popa. "Firecracker: Lightweight Virtualization for Serverless Applications." In *Proceedings of the 17th USENIX Symposium on Networked Systems Design and Implementation* (NSDI 2020), 2020. [12] Jay Bosamiya, Wen Shih Lim, and Bryan Parno. "Provably-Safe Multilingual Software Sandboxing using WebAssembly." In *Proceedings of the 31st USENIX Security Symposium* (USENIX Security 2022), 2022. (Distinguished Paper Award.) [13] Jack B. Dennis and Earl C. Van Horn. "Programming Semantics for Multiprogrammed Computations." *Communications of the ACM*, Vol. 9, No. 3, pp. 143–155, 1966. DOI: 10.1145/365230.365252. [14] Gerwin Klein, Kevin Elphinstone, Gernot Heiser, June Andronick, David Cock, Philip Derrin, Dhammika Elkaduwe, Kai Engelhardt, Rafal Kolanski, Michael Norrish, Thomas Sewell, Harvey Tuch, and Simon Winwood. "seL4: Formal Verification of an OS Kernel." In *Proceedings of the 22nd ACM Symposium on Operating Systems Principles* (SOSP '09), 2009. DOI: 10.1145/1629575.1629596. [15] Robert N. M. Watson, Jonathan Anderson, Ben Laurie, and Kris Kennaway. "Capsicum: practical capabilities for UNIX." In *Proceedings of the 19th USENIX Security Symposium* (USENIX Security '10), 2010. [16] Henry M. Levy. *Capability-Based Computer Systems*. Digital Press, 1984. (Book.) [17] Ian Goldberg, David Wagner, Randi Thomas, and Eric A. Brewer. "A Secure Environment for Untrusted Helper Applications: Confining the Wily Hacker." In *Proceedings of the 6th USENIX Security Symposium*, July 1996. [18] Igor Santos-Grueiro. "Lingering Authority: Revocable Resource-and-Effect Capabilities for Coding Agents." arXiv:2606.22504, 2026. (Single-author preprint; no peer-reviewed venue as of this writing.) [19] Rafiqul Rabin, Jesse Hostetler, Sean McGregor, Brett Weir, and Nick Judd. "SandboxEval: Towards Securing Test Environment for Untrusted Code." arXiv:2504.00018, 2025. (Preliminary version; working paper.) [20] Rashid Amin, Sajid Mehmood, Syafiq Fauzi Kamarulzaman, Antonio Costanzo, Faisal S. Alsubaei, and Asma Hassan Alshehri. "AutoSec-Agent: a fully autonomous and ethical multi-agent framework for scalable penetration testing using large language models." *Complex & Intelligent Systems* (Springer), 2026. DOI: 10.1007/s40747-026-02447-5. [21] Junyong Jiang. "Runtime Protection Practice for LLM Agent Security: An On-Demand Behavioral Sandbox Approach." In *2026 11th International Symposium on Advances in Electrical, Electronics and Computer Engineering* (ISAEECE), IEEE, pp. 587–590, 2026. DOI: 10.1109/isaeece70502.2026.11635191. [22] Shishir G. Patil, Tianjun Zhang, Vivian Fang, Noppapon C., Roy Huang, Aaron Hao, Martin Casado, Joseph E. Gonzalez, Raluca Ada Popa, and Ion Stoica. "GoEX: Perspectives and Designs Towards a Runtime for Autonomous LLM Applications." arXiv:2404.06921, 2024.