# Diagrams — Module B7: Sandboxes and Execution Controls

**Module**: B7 — Sandboxes and Execution Controls
**Diagram count**: 5
**Tool**: Mermaid (primary). Each diagram validated in [Mermaid Live Editor](https://mermaid.live).

---

## Diagram 1 — The Isolation Hierarchy: Blast Radius vs. Overhead

**Type**: Spectrum / tradeoff curve
**Purpose**: The single most important visual in the module. Every sandbox technology is a point on the tradeoff curve between **isolation strength** (the blast radius if the contained code is hostile) and **overhead** (cold-start latency, memory density, operational cost). The correct point depends on *what code runs and who chose it* — operator-written code tolerates process isolation; agent-written code under coercion needs a microVM or WASM isolate. The hierarchy is the curve; "plain Docker for everything" is the defect this module exists to fix.
**Reading the diagram**: Read left-to-right as increasing isolation strength (decreasing blast radius) and increasing overhead. Each node carries its escape surface. Note that plain Docker's boundary is the Linux kernel — a CVE-rich surface — while Firecracker's is a stripped, audited hypervisor.

```mermaid
flowchart LR
  P["OS PROCESS<br/>UID/gid boundary<br/>cold start: instant"]:::weak
  D["CONTAINER<br/>Docker / Podman<br/>namespaces + cgroups<br/>boundary = the kernel"]:::weak
  G["HARDENED CONTAINER<br/>gVisor (userspace kernel)<br/>Kata (lightweight VM)<br/>boundary = runsc / hypervisor"]:::mid
  F["MICROVM<br/>Firecracker<br/>~125ms cold start<br/>boundary = stripped hypervisor"]:::strong
  W["WASM / V8 ISOLATE<br/>Wasmtime · isolated-vm<br/>cold start: ms<br/>boundary = the runtime + exports"]:::strong
  V["FULL VM<br/>KVM · Hyper-V<br/>strongest isolation<br/>boundary = hypervisor"]:::strong

  P --> D --> G --> F --> W --> V

  BLAST["BLAST RADIUS  (decreases →)"]:::label
  OVER["OVERHEAD  (increases →)"]:::label
  P -.-> BLAST
  V -.-> OVER

  classDef weak fill:#14141f,stroke:#f08080,stroke-width:1.5px,color:#f08080
  classDef mid fill:#14141f,stroke:#f0a868,stroke-width:1.5px,color:#f0a868
  classDef strong fill:#14141f,stroke:#82e0aa,stroke-width:1.5px,color:#82e0aa
  classDef label fill:#101018,stroke:#5eead4,color:#9494a0
```

> **Note**: The arrow is the tradeoff. Moving right buys a smaller blast radius at the cost of cold-start latency, memory, and operational complexity. The defect in most shipped agent sandboxes is sitting at level 2 (plain Docker) regardless of what code runs inside — the Linux kernel is the boundary, and the kernel has CVEs. gVisor or Kata is the floor for agent code; Firecracker or WASM for code the agent was coerced into running. Reference: NemoClaw's OpenShell (DD-09) brokers every execution through the governed API regardless of where the sandbox sits on this curve.

---

## Diagram 2 — The Four Attack Vectors Against a Sandbox

**Type**: Attack-surface map
**Purpose**: When injection succeeds (ASI07) and the agent is coerced into running attacker-chosen code inside the sandbox, four vectors by which that code attacks the *system*, not just the sandbox. The diagram maps each vector to the asset it threatens and the control that contains it. Vectors 2 (egress) and 3 (resource exhaustion, ASI09) are the under-applied ones.
**Reading the diagram**: The sandbox sits at the center. Each red arrow is an attack vector outward to an asset. Each green box is the control. Vector 1 (escape) is contained by the blast-radius principle (B7.3), not by prevention alone — assume it succeeds.

```mermaid
flowchart TB
  HOST["HOST<br/>kernel · credentials · network"]
  SUB["SANDBOX<br/>attacker-chosen code<br/>coerced via ASI07 injection"]:::danger

  HOST -->|contains| SUB

  V1["VECTOR 1 — ESCAPE<br/>exploit a bug in the provider<br/>(V8 · kernel · gVisor)<br/>reach the host"]:::danger
  V2["VECTOR 2 — NETWORK EGRESS<br/>exfiltrate · C2 · lateral move<br/>SSRF the metadata service"]:::danger
  V3["VECTOR 3 — RESOURCE EXHAUSTION<br/>ASI09 · run forever<br/>fill disk · OOM · fork-bomb"]:::danger
  V4["VECTOR 4 — SIDECAR COMPROMISE<br/>suborn a privileged helper<br/>(root package installer,<br/>format converter)"]:::danger

  SUB --> V1 --> HOST
  SUB --> V2
  SUB --> V3
  SUB --> V4 --> HOST

  C1["CONTROL — blast-radius principle<br/>no creds · no network · assume escape<br/>(stronger point on the hierarchy)"]:::good
  C2["CONTROL — default-deny egress<br/>per-task allowlist at the network layer<br/>(NOT the LLM-judge layer)"]:::good
  C3["CONTROL — hard resource caps<br/>CPU · mem · proc · disk<br/>cgroup-enforced, per task"]:::good
  C4["CONTROL — privilege minimization<br/>no root helpers · capability-scoped IPC<br/>validating registry proxy"]:::good

  V1 -. contained by .-> C1
  V2 -. contained by .-> C2
  V3 -. contained by .-> C3
  V4 -. contained by .-> C4

  classDef danger fill:#14141f,stroke:#f08080,stroke-width:1.5px,color:#f08080
  classDef good fill:#14141f,stroke:#82e0aa,stroke-width:1.5px,color:#82e0aa
  style HOST fill:#14141f,stroke:#5eead4,stroke-width:1.5px,color:#e4e4e8
  style SUB fill:#14141f,stroke:#f08080,stroke-width:2px,color:#f08080
  style C1 fill:#101018,stroke:#82e0aa,color:#9494a0
  style C2 fill:#101018,stroke:#82e0aa,color:#9494a0
  style C3 fill:#101018,stroke:#82e0aa,color:#9494a0
  style C4 fill:#101018,stroke:#82e0aa,color:#9494a0
```

> **Note**: Vectors 1 and 4 reach the host directly; vectors 2 and 3 stay in the sandbox but harm the system (exfiltration, denial-of-service/cost). Vector 2 (egress) is the most under-applied control — operators fixate on the filesystem mis-scope that *coughs up* the secret and ignore the network that *carries it out*. Default-deny egress contains the larger class of outcomes. Vector 3 (ASI09) is contained by cgroup caps, not by "the agent will behave."

---

## Diagram 3 — Default-Deny Network Egress (the Network-Layer Model)

**Type**: Policy model
**Purpose**: The sandbox's network namespace starts with egress denied to everything. Each task (or tool) carries an allowlist. Enforcement is at the **network layer** (iptables/nftables, an egress proxy, or the microVM's restricted NIC) — *not* the LLM-judge layer (CrabTrap, DD-19). The two are complementary: the network layer answers the *existence* question ("should this sandbox reach the network at all?") deterministically; the LLM judge answers the *semantic* question probabilistically. The metadata service (169.254.169.254) is blocked by default — it hands out cloud-instance credentials to anything that reaches it.
**Reading the diagram**: Left = the default state (deny everything). Right = the per-task allowlist. The metadata endpoint is highlighted as the must-block special case. CrabTrap sits *on top of* the network-layer gate, not in place of it.

```mermaid
flowchart LR
  SANDBOX["SANDBOX<br/>network namespace<br/>default state: DENY ALL"]:::danger

  EGRESS["EGRESS GATE<br/>network-layer enforcement<br/>iptables / egress proxy / microVM NIC"]:::gate

  MD["169.254.169.254<br/>CLOUD METADATA<br/>hands out instance creds<br/>ALWAYS BLOCKED"]:::blocked
  INet["PUBLIC INTERNET<br/>default: blocked"]:::blocked

  ALLOW1["task: web_search<br/>→ search.example-corp.net"]:::allow
  ALLOW2["task: fetch_docs<br/>→ docs.spec.host"]:::allow
  ALLOW3["task: install_deps<br/>→ validating registry only"]:::allow

  SANDBOX --> EGRESS
  EGRESS -. default deny .-> MD
  EGRESS -. default deny .-> INet
  EGRESS -->|per-task allowlist| ALLOW1
  EGRESS -->|per-task allowlist| ALLOW2
  EGRESS -->|per-task allowlist| ALLOW3

  JUDGE["CrabTrap (DD-19)<br/>LLM-as-judge egress proxy<br/>sits ON TOP — answers the<br/>SEMANTIC question probabilistically<br/>(does NOT replace this layer)"]:::note
  EGRESS -. complements .-> JUDGE

  classDef danger fill:#14141f,stroke:#f08080,stroke-width:1.5px,color:#f08080
  classDef gate fill:#14141f,stroke:#5eead4,stroke-width:2px,color:#5eead4
  classDef blocked fill:#101018,stroke:#f08080,color:#f08080
  classDef allow fill:#101018,stroke:#82e0aa,color:#82e0aa
  classDef note fill:#101018,stroke:#f0a868,color:#f0a868
```

> **Note**: The network-layer default-deny is the control that must hold when the LLM judge is bypassed, confused, or absent. A sandbox that relies on CrabTrap alone for egress governance is one prompt-injection of the judge away from exfiltration. The metadata endpoint deserves special callout: a sandboxed agent that can reach `169.254.169.254` can steal the host's cloud role — a far worse outcome than reading a local secret. Block it at the network layer, always.

---

## Diagram 4 — The Sidecar Monitor Architecture

**Type**: Component / data-flow
**Purpose**: The sidecar monitor is a process that observes the sandbox from *outside* its trust boundary — the contained code cannot reach it to disable it. It watches four signal classes (resource, syscall, network, behavioral) and feeds B8's observability pipeline. The monitor *detects*; the controls in B7.2 *prevent*. The two are complementary: a sandbox with monitoring but no policy is a sandbox that alerts on every attack and stops none.
**Reading the diagram**: The monitor sits beside (not inside) the sandbox. Each signal class feeds into event emission. The events correlate with the agent's tool-call trace so an investigator can reconstruct the attack timeline. Out-of-band = the contained code has no path to disable or tamper with the monitor.

```mermaid
flowchart TB
  SUB["SANDBOX<br/>contained code<br/>(the agent, possibly coerced)"]:::danger

  subgraph OUT["OUT-OF-BAND — outside the sandbox trust boundary"]
    direction TB
    M["SIDECAR MONITOR<br/>cannot be reached by the contained code"]
    S1["RESOURCE signals<br/>CPU · mem · disk · proc count<br/>threshold = ASI09 / escape-in-progress"]:::sig
    S2["SYSCALL signals<br/>seccomp-bpf · eBPF · gVisor log<br/>grep issuing socket()+connect()+fork()"]:::sig
    S3["NETWORK signals<br/>connection attempts (allowed+denied)<br/>DNS · byte volumes<br/>denied-burst = C2 attempt"]:::sig
    S4["BEHAVIORAL signals<br/>repeated failures · odd command seq<br/>git from inside the pytest tool"]:::sig
    M --> S1
    M --> S2
    M --> S3
    M --> S4
  end

  SUB -. observed .-> M

  S1 --> EV["STRUCTURED EVENTS"]
  S2 --> EV
  S3 --> EV
  S4 --> EV

  EV --> CORR["CORRELATE with agent<br/>tool-call trace"]
  CORR --> B8["→ B8 OBSERVABILITY<br/>reconstruct: coerced @ step 14,<br/>ran cmd @ 15, egress denied @ 16,<br/>flagged @ 17"]
  CORR --> ALERT["ALERT / kill sandbox<br/>unexpected process tree<br/>or syscall profile"]:::danger

  classDef danger fill:#14141f,stroke:#f08080,stroke-width:1.5px,color:#f08080
  classDef sig fill:#101018,stroke:#f0a868,color:#e4e4e8
  style SUB fill:#14141f,stroke:#f08080,stroke-width:2px,color:#f08080
  style M fill:#14141f,stroke:#5eead4,stroke-width:1.5px,color:#5eead4
  style EV fill:#101018,stroke:#5eead4,color:#9494a0
  style CORR fill:#101018,stroke:#5eead4,color:#9494a0
  style B8 fill:#101018,stroke:#82e0aa,color:#82e0aa
  style ALERT fill:#101018,stroke:#f08080,color:#f08080
```

> **Note**: The monitor's "out-of-band" position is load-bearing. A monitor that runs *inside* the sandbox is a monitor the contained code can kill before misbehaving — the eBPF/Falco pattern (kernel-level, host-side) exists precisely because userspace-in-sandbox monitoring is untrustworthy. The four signal classes cover all four attack vectors from Diagram 2: resource (V3), syscall (V1 escape attempts), network (V2), behavioral (V4 sidecar). Denied-connection bursts are especially informative — they are the contained code *trying* to reach something the policy blocked.

---

## Diagram 5 — The Blast-Radius Principle: An Escaped Sandbox Has Nothing

**Type**: Principle illustration
**Purpose**: The central design philosophy of the module. The naive intuition is "harden the sandbox so it cannot be escaped." The correct goal: **assume the sandbox will be escaped, and design so an escaped sandbox still has no credentials and no network.** The escape becomes a detected-and-killed anomaly, not an incident. Three realizations: credential quarantine (IronCurtain's fake-key swap), network default-deny (the namespace survives escape), and no privileged helpers.
**Reading the diagram**: The contained code escapes (red path, right side) and reaches the host. What it finds: no credentials (quarantined), no network (namespace default-deny still holds), no privileged helper (all minimum-privilege). The monitor detects the unexpected process tree / syscalls and kills the sandbox. The escape is contained.

```mermaid
flowchart LR
  subgraph SBX["THE SANDBOX — assume it WILL be escaped"]
    CODE["contained code<br/>(attacker-chosen,<br/>coerced via ASI07)"]:::danger
    FAKE["fake API keys only<br/>(credential quarantine)"]:::good
    NONET["network namespace<br/>default-deny"]:::good
    CODE --> FAKE
    CODE --> NONET
  end

  ESC["ESCAPE<br/>bug in V8 / kernel / gVisor<br/>contained code reaches host"]:::danger
  CODE -->|exploits provider CVE| ESC

  subgraph HOSTSTATE["WHAT THE ESCAPED CODE FINDS ON THE HOST"]
    direction TB
    NOCRED["NO CREDENTIALS<br/>real keys never entered the sandbox<br/>MITM proxy held them at the boundary"]:::good
    NONET2["NO NETWORK<br/>the namespace's default-deny<br/>survives the escape"]:::good
    NOHELP["NO PRIVILEGED HELPER<br/>every subprocess is min-privilege,<br/>capability-scoped IPC"]:::good
  end

  ESC --> HOSTSTATE

  MON["SIDECAR MONITOR<br/>detects: unexpected process tree,<br/>syscalls outside task profile<br/>→ KILL SANDBOX"]:::good
  HOSTSTATE -. observed .-> MON

  OUT["RESULT<br/>escape is a contained anomaly<br/>NOT an incident<br/>(worst case: a killed sandbox)"]:::good
  MON --> OUT

  classDef danger fill:#14141f,stroke:#f08080,stroke-width:1.5px,color:#f08080
  classDef good fill:#14141f,stroke:#82e0aa,stroke-width:1.5px,color:#82e0aa
  style CODE fill:#101018,stroke:#f08080,color:#f08080
  style FAKE fill:#101018,stroke:#82e0aa,color:#9494a0
  style NONET fill:#101018,stroke:#82e0aa,color:#9494a0
  style ESC fill:#14141f,stroke:#f08080,stroke-width:2px,color:#f08080
  style NOCRED fill:#101018,stroke:#82e0aa,color:#e4e4e8
  style NONET2 fill:#101018,stroke:#82e0aa,color:#e4e4e8
  style NOHELP fill:#101018,stroke:#82e0aa,color:#e4e4e8
  style MON fill:#14141f,stroke:#5eead4,stroke-width:1.5px,color:#5eead4
  style OUT fill:#101018,stroke:#82e0aa,color:#82e0aa
```

> **Note**: The principle, compressed: **the value of escape is what you can reach after escaping.** Design so the answer is "nothing." Then the sandbox's isolation technology (Diagram 1) becomes a *probability reducer*, not a single point of failure. IronCurtain's credential quarantine is the strongest realization studied in the course — even a fully compromised agent cannot exfiltrate real credentials because it does not have them. If your architecture requires credentials *in* the sandbox (the inside-sandbox model from Course 1 Module 5), you have accepted a worse blast radius; document the decision and reinforce the other two realizations.
