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.


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.

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.

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.

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.

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.

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.

# 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.