Sandboxes and Execution Controls

Module B7 · Course 2B — Securing & Attacking Harnesses and LLMs

60 minutes · The sandbox is the last line of defense — assume it will be escaped and design so escape does not matter

Injection will succeed (ASI07). The agent will be coerced into running code. The sandbox is what decides whether that means a confused log line or a reverse shell on your jump host.

Pillar 3 — Controls

The inversion from Course 1 Module 5

Course 1 Module 5 taught you how to build a sandbox. B7 teaches you how the sandbox fails under an adversary who controls the agent's inputs.

Course 1 — honest agent

Threat: a misbehaving-but-honest agent. An over-long loop. A mis-scoped write. The sandbox contains accidents.

Course 2B — coerced agent

Threat: an agent under prompt-injection coercion, induced to run attacker-chosen code inside your sandbox. The controls must be stronger, the threat model is adversarial, and the design philosophy inverts.

The inversion, restated as a philosophy

Naive intuition: harden the sandbox so it cannot be escaped.
B7's principle: assume the sandbox will be escaped, and design so that an escaped sandbox still has no credentials and no network. The escape becomes a detected-and-killed anomaly, not an incident.

Every sandbox is software; every sandbox has CVEs; every sandbox will, eventually, be escaped. The value of escape is what you can reach after escaping. Design so the answer is "nothing."

B7.1 — The sandbox hierarchy and the escape threat

Isolation strength vs. overhead, and the four attack vectors

The isolation hierarchy

LevelBoundaryEscape surface
OS processUID/gid + kernelThe whole user account
Container (Docker)namespaces + cgroupsThe Linux kernel (CVE-rich)
Hardened containergVisor (userspace kernel) / Kata (lightweight VM)runsc / hypervisor
MicroVM (Firecracker)stripped KVM hypervisorsmall, audited hypervisor
WASM / V8 isolatelinear memory + capability exportsthe runtime + your exports
Full VMKVM / Hyper-Vhypervisor (rarely the right answer)
The defect in most shipped sandboxes: plain Docker for everything. The kernel is the boundary. For agent code, gVisor/Kata is the floor; Firecracker or WASM for code the agent was coerced into running.

The four attack vectors

VectorWhat it doesControl
1. EscapeExploit a bug in the provider (V8, kernel, gVisor) to reach the hostBlast-radius principle (assume it)
2. Network egressExfiltrate, C2, lateral move, SSRF metadataDefault-deny egress (most under-applied)
3. Resource exhaustion (ASI09)Run forever, fill disk, OOM, fork-bombHard resource caps (cgroups)
4. Sidecar compromiseSuborn a privileged helper (root installer)Privilege minimization on helpers
Vector 2 is the one operators ignore. They fixate on the filesystem mis-scope that coughs up the secret and ignore the network that carries it out. Default-deny contains the larger class of outcomes.

B7.2 — Execution policies and network segmentation

What code may run, and what the sandbox may reach

Allowlists, not denylists

Denylist = "things you have thought of." Block curl, then wget, then python -c, then perl, then git clone with a hook. The space of "things that fetch a URL or run code" is unbounded.
Allowlist = "things the task needs." ls, cat, grep, git status, pytest. The attacker's job becomes: make an allowed command do harm (argument injection) — a bounded, auditable surface.

The stronger pattern: per-tool execution scopes. The run_tests tool may invoke pytest; the install_deps tool may not. The sandbox enforces "command matches the calling tool's scope" before exec.

Deterministic enforcement (IronCurtain, not CrabTrap)

LLM-as-judge at runtime (CrabTrap model applied to execution)
Flexible — novel attacks caught.
Probabilistic — a prompt injection in the arguments can manipulate the judge. For security-critical decisions, a defect.
Deterministic compilation (IronCurtain model)
Policy written in English, compiled offline to JSON rules. At runtime: pure if/then matching. Zero LLM at runtime. Miscompilation caught by verify-and-repair at build time.
Principle: security-critical runtime decisions must be deterministic. The allowlist for a tool's command surface is a finite, enumerable set — there is no semantic question the LLM needs to answer at runtime.

Default-deny network egress

SANDBOX network namespace
  │  default state: DENY ALL
  ▼
EGRESS GATE (network-layer: iptables / proxy / microVM NIC)
  │
  ├─ 169.254.169.254  → ALWAYS BLOCKED (hands out cloud creds)
  ├─ public internet   → default blocked
  │
  └─ per-task allowlist:
       web_search    → search.example-corp.net
       fetch_docs    → docs.spec.host
       install_deps  → validating registry ONLY
Distinct from CrabTrap. CrabTrap (DD-19) answers the semantic egress question probabilistically (LLM judge). The network-layer gate answers the existence question deterministically. You want both — and the network layer is what holds when the judge is bypassed, confused, or absent.

B7.3 — Sidecar monitors and the blast-radius principle

Detection, and the design discipline that makes escape survivable

The sidecar monitor — out-of-band

A process that observes the sandbox from outside its trust boundary — the contained code cannot reach it to disable it. It detects; the controls in B7.2 prevent.

Signal classWhat it catches
ResourceCPU/mem/disk/proc spikes → ASI09 or escape in progress
Syscall (eBPF, seccomp, gVisor log)grep issuing socket()+connect()+fork()
NetworkDenied-connection bursts → C2 attempt signature
Behavioralgit invoked from inside the pytest tool
Output feeds B8's observability pipeline, correlated with the agent's tool-call trace: "coerced @ step 14, ran cmd @ 15, egress denied @ 16, flagged @ 17."

The blast-radius principle: three realizations

1. No credentials in the sandbox. IronCurtain's fake-key swap: the agent holds only fakes; a MITM proxy substitutes reals at the boundary. An escaped agent has no real credentials to exfiltrate.
2. No network from the sandbox. The namespace's default-deny survives the escape — the contained code reaching the host kernel does not gain a new NIC.
3. No privileged helpers. Every subprocess is minimum-privilege, capability-scoped IPC. The contained code that escapes and suborns a helper finds helpers that are themselves locked down.

Reference architectures

ProjectContribution to B7
OpenShell (DD-09, NemoClaw)The reference sandbox: the agent never touches the sandbox directly — execution goes through the governed API.
CrabTrap (DD-19, Brex)LLM-as-judge egress proxy. The semantic egress layer; complements (does not replace) network-layer default-deny.
IronCurtain (DD-20, Provos)Deterministic enforcement + credential quarantine. The reference defense architecture: zero LLM at runtime, agent never holds real keys.
Three projects, three layers: OpenShell brokers execution, CrabTrap judges semantics, IronCurtain quarantines credentials and compiles policy deterministically. Together they approximate the blast-radius principle.

Lab & what's next

Lab (07): build the Sandbox Policy Enforcer — (a) allowlist command gate with per-tool scopes, (b) cgroup-enforced resource caps, (c) default-deny egress gate with per-task allowlisting. Then attempt to reach the network from inside and watch the gate deny it.

Next — B8: Observability and Attack Detection. The sidecar monitor's events feed B8's pipeline. Detection is the layer that tells you when the B7 controls engaged on a real attack — and reconstructs the coercion-to-exfiltration timeline.