Diagrams — Module S00: Legal, Ethics, and Rules of Engagement

All Mermaid validated in Mermaid Live Editor. n8n JSON is structurally valid and importable.


Diagram 1 — The Authorization Chain (and where it breaks)

Type: Mermaid (flowchart with break annotations) Purpose: The central visual of S00.1. Authorization is a chain from asset owner to atomic tool call. A break anywhere voids downstream cover. Three named breaks correspond to the three failure modes in the teaching doc.

flowchart TD
    OWNER["Asset Owner<br/>owns the system under test"]
    SPONSOR["Program / Engagement Sponsor<br/>operates the bounty or pentest"]
    POLICY["Program Policy / SOW<br/>scope · RoE · safe harbor · evidence rules"]
    SCOPE["Scope File (JSON)<br/>machine-checkable boundary"]
    MW["Scope Enforcement Middleware<br/>intercepts every outbound call"]
    CALL["Tool Call<br/>nmap · http · ffuf · exploit"]

    OWNER -->|chain of title| SPONSOR
    SPONSOR -->|warrants owner auth| POLICY
    POLICY -->|formalized| SCOPE
    SCOPE -->|loaded into| MW
    MW -->|permits only if in-scope| CALL

    BREAK1(("BREAK 1<br/>Sponsor ≠ Owner"))
    BREAK2(("BREAK 2<br/>Action outside RoE"))
    BREAK3(("BREAK 3<br/>Stale scope"))

    BREAK1 -.voids.-> SPONSOR
    BREAK2 -.voids.-> MW
    BREAK3 -.voids.-> SCOPE

    style OWNER fill:#0d1b2a,stroke:#5eead4,color:#e4e4e8
    style SPONSOR fill:#101018,stroke:#5a5a68,color:#e4e4e8
    style POLICY fill:#101018,stroke:#5a5a68,color:#e4e4e8
    style SCOPE fill:#14141f,stroke:#5eead4,color:#e4e4e8
    style MW fill:#14141f,stroke:#5eead4,color:#5eead4
    style CALL fill:#101018,stroke:#5a5a68,color:#9494a0
    style BREAK1 fill:#2a0d0d,stroke:#a00000,color:#f08080
    style BREAK2 fill:#2a0d0d,stroke:#a00000,color:#f08080
    style BREAK3 fill:#2a0d0d,stroke:#a00000,color:#f08080

Reading the diagram: Read top-down. Each arrow is a link in the chain — and the only place legal cover is created is at the top (the asset owner's consent). The three red BREAK nodes are where the chain voids in practice. Break 1: a program operator that doesn't actually hold the owner's authorization. Break 2: an action the RoE forbids, even on an in-scope host. Break 3: a scope file that was valid last week but whose targets were since removed. The scope enforcement middleware (teal) is the engineering realization of the chain — it converts "is this call authorized?" into a binary, code-level check.


Diagram 2 — Scope Enforcement as Harness Middleware (n8n)

Type: n8n workflow (importable JSON) Purpose: The primary visual per the course tech stack (n8n first). Shows scope enforcement as a middleware node that sits between the agent's tool request and the network — the load-bearing architectural pattern of S01.2, previewed here in its legal-control framing.

{
  "name": "S00 — Scope Enforcement Middleware",
  "nodes": [
    {
      "parameters": {},
      "name": "Tool Request",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [240, 300],
      "notes": "Agent (or sub-agent) emits a tool_use: {tool, target, action}"
    },
    {
      "parameters": {
        "dataType": "string",
        "value1": "={{ $json.target }}",
        "rules": {
          "rules": [
            { "value2": "={{ $env.SCOPE_IN_SCOPE.split(',') }}", "operation": "isInList" }
          ]
        }
      },
      "name": "Target in Scope?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1.1,
      "position": [460, 300],
      "notes": "Check target against scope.in_scope[]. Match is exact, not glob."
    },
    {
      "parameters": {
        "dataType": "string",
        "value1": "={{ $json.action }}",
        "rules": {
          "rules": [
            { "value2": "={{ $env.ROE_FORBIDDEN.split(',') }}", "operation": "notInList" }
          ]
        }
      },
      "name": "Action under RoE?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1.1,
      "position": [680, 300],
      "notes": "Check action against rules_of_engagement.forbidden[]. e.g. 'dos','exfil','socialeng'"
    },
    {
      "parameters": {
        "dataType": "dateTime",
        "value1": "={{ $now.toISO() }}",
        "rules": {
          "rules": [
            { "value2": "={{ $env.SCOPE_VALID_UNTIL }}", "operation": "before" }
          ]
        }
      },
      "name": "Scope Fresh?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1.1,
      "position": [900, 300],
      "notes": "Reject if scope.valid_until has passed. Prevents stale-scope drift (Break 3)."
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            { "name": "scope_ref", "value": "={{ $json.target }}::{{ $json.action }}::{{ $now.toISO() }}" }
          ]
        }
      },
      "name": "Stamp scope_ref",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [1120, 240],
      "notes": "Annotate the call with the scope entry that authorized it. This is the legal anchor in the evidence log."
    },
    {
      "parameters": {},
      "name": "Execute Tool",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [1320, 240],
      "notes": "Only reached if all three checks pass. The network call happens here."
    },
    {
      "parameters": {
        "values": {
          "string": [
            { "name": "blocked_reason", "value": "out_of_scope" }
          ]
        }
      },
      "name": "Block + Log",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [1120, 360],
      "notes": "Blocked call. Logged with reason. Never reaches the network. This is the legal control."
    }
  ],
  "connections": {
    "Tool Request": { "main": [[{ "node": "Target in Scope?", "type": "main", "index": 0 }]] },
    "Target in Scope?": { "main": [[{ "node": "Action under RoE?", "type": "main", "index": 0 }], [{ "node": "Block + Log", "type": "main", "index": 0 }]] },
    "Action under RoE?": { "main": [[{ "node": "Scope Fresh?", "type": "main", "index": 0 }], [{ "node": "Block + Log", "type": "main", "index": 0 }]] },
    "Scope Fresh?": { "main": [[{ "node": "Stamp scope_ref", "type": "main", "index": 0 }], [{ "node": "Block + Log", "type": "main", "index": 0 }]] },
    "Stamp scope_ref": { "main": [[{ "node": "Execute Tool", "type": "main", "index": 0 }]] }
  }
}

Reading the diagram: A tool request enters from the agent. Three sequential IF gates — target in scope, action permitted by RoE, scope not stale — each can divert to Block+Log. Only a request passing all three reaches the network. The scope_ref stamp is the legal anchor: it records which scope entry authorized this call at this time, producing the "authorization chain to the atom" that protects the operator if the call is ever questioned. This is the n8n shape of the pattern S01.2 implements in code.


Diagram 3 — The Gates-Down Model (post-Van Buren CFAA authorization)

Type: Mermaid (statechart) Purpose: Makes the Van Buren v. United States (2021) ruling concrete. Authorization is assessed at the "gate" (the file/folder/host boundary), not at the motive layer. A harness must treat each gate as binary.

stateDiagram-v2
    [*] --> Unauth: target never authorized
    [*] --> Auth: scope file permits target

    Unauth --> VIOLATION: any access
    note right of VIOLATION
        § 1030(a)(2): access without authorization.
        Van Buren offers NO shelter here.
        The gate was never opened.
    end note

    Auth --> AuthorizedArea: access permitted file/host
    Auth --> Exceeded: access file/host NOT in scope
    note right of Exceeded
        "Exceeds authorized access" (post-Van Buren):
        accessing an area you are NOT authorized
        to access at all. Not a motive question.
    end note

    AuthorizedArea --> OK: used for security testing
    AuthorizedArea --> STILL_OK: used for improper purpose
    note left of STILL_OK
        Van Buren: improper purpose on an
        authorized area is NOT a CFAA (a)(2)
        violation. Gates-down, not motives-down.
    end note

    Exceeded --> VIOLATION
    OK --> [*]
    STILL_OK --> [*]
    VIOLATION --> [*]

Reading the diagram: Two entry states — the target is either in your scope file (Auth) or not (Unauth). From Auth, you either stay in an authorized area or exceed into one you were never granted. The Van Buren holding is the lower-left: improper purpose on an authorized area is not an (a)(2) violation — that is the narrowing. The critical warning for harness builders is the right side: "exceeds authorized access" still cleanly captures reaching an area the scope file never permitted. The narrowing moved the motive inquiry; it did not move the gate. Build the gate (scope enforcement), not a motive detector.


Diagram 4 — When Scanning Becomes DoS (effect-based, not rate-based)

Type: Mermaid (flowchart with threshold) Purpose: The CFAA § 1030(a)(5) / CMA s.3 risk model. There is no bright-line request rate. The threshold is effect on the target. Shows the harness's required reaction to distress signals.

flowchart LR
    subgraph SCAN["Scanner at rate R"]
        S1["Outbound requests"]
    end

    S1 --> T1{"Target showing<br/>distress?"}
    T1 -->|"5xx spike"| DISTRESS
    T1 -->|"conn resets"| DISTRESS
    T1 -->|"latency spike"| DISTRESS
    T1 -->|"rate-limit hit"| DISTRESS
    T1 -->|"none"| CONTINUE

    DISTRESS["Distress signal<br/>detected"]
    CONTINUE["Continue at R"]

    DISTRESS --> REACT{"Harness reaction"}
    REACT -->|"back off (R/2)"| SCAN
    REACT -->|"threshold exceeded"| HALT

    HALT["STOP — stop condition<br/>this is a CFAA (a)(5) mitigation,<br/>not a performance tweak"]

    style DISTRESS fill:#2a1810,stroke:#a04000,color:#f0a868
    style HALT fill:#2a0d0d,stroke:#a00000,color:#f08080
    style SCAN fill:#0d1b2a,stroke:#1b4f72,color:#e4e4e8
    style CONTINUE fill:#0d2818,stroke:#1e8449,color:#82e0aa

Reading the diagram: The threshold between "scanning" and "DoS" is the target's distress, not your request rate. A scanner at 5 req/s that takes down a fragile target is a DoS; a scanner at 500 req/s against a hardened one may be fine. The harness cannot know in advance which is which — so it must react to distress signals (5xx spikes, connection resets, latency degradation, rate-limit responses) by backing off, and halt entirely if distress persists. That halt is a stop condition (Course 1, Module 1.2) and its legal function is a § 1030(a)(5) mitigation. Default to low concurrency; back off on distress; treat persistent distress as a hard stop.


Diagram 5 — The Evidence Record and its Retention Lifecycle

Type: Mermaid (flowchart + statechart hybrid) Purpose: S00.2's two-sided evidence obligation. A finding record has a lifecycle: capture → classify → retain or destroy. The classification determines the retention. Over-retention is as much a liability as under-retention.

flowchart TD
    FIND["Finding detected"]
    CAP["Capture minimum proof<br/>COUNT(*) or 1 redacted row<br/>NOT SELECT *"]

    CAP --> CLASS{"Classify"}

    CLASS -->|"no sensitive data"| PUB["Public"]
    CLASS -->|"redacted at capture"| RED["Redacted"]
    CLASS -->|"real PII / credentials"| REST["Restricted"]

    PUB --> KEEP1["Retain indefinitely<br/>(portfolio artifact)"]
    RED --> KEEP2["Retain for engagement<br/>+ contractual tail"]
    REST --> DESTROY["Destroy on report<br/>or per contract<br/>(whichever sooner)"]

    KEEP1 --> LOG["Evidence store<br/>(append-only, scope-referenced)"]
    KEEP2 --> LOG
    DESTROY --> DELETED["Documented destruction<br/>(record the deletion, not the data)"]

    LOG --> REPORT["Ties finding to scope_ref<br/>from Diagram 2"]

    style CAP fill:#0d1b2a,stroke:#1b4f72,color:#e4e4e8
    style DESTROY fill:#2a0d0d,stroke:#a00000,color:#f08080
    style DELETED fill:#101018,stroke:#5a5a68,color:#9494a0
    style REST fill:#2a1810,stroke:#a04000,color:#f0a868
    style LOG fill:#14141f,stroke:#5eead4,color:#5eead4

Reading the diagram: Capture is the first decision point — and it is minimum proof, by default. The classification gate routes each record to a retention class. Public records can live forever as portfolio artifacts; Redacted records survive the engagement plus a tail; Restricted records (real PII, credentials) are destroyed on report submission. The destruction is itself recorded (you keep the record of the deletion, not the deleted data). The evidence store at the bottom is the same append-only, scope-referenced log from Diagram 2 — every record carries the scope_ref that authorized the call that produced it. An evidence store that captures everything and destroys nothing has built a compliance time bomb, not an evidence chain.


Diagram 6 — Coordinated Vulnerability Disclosure Timeline

Type: Mermaid (sequence/gantt-style flow) Purpose: The CVD baseline. The harness must emit disclosure metadata (report date, vendor response, agreed publication date) as part of every finding — this diagram shows why those fields exist.

flowchart LR
    D0["Day 0<br/>Discovery +<br/>private report"]
    D0 -->|"vendor ack"| D1["Day 1–7<br/>Vendor triage<br/>(expected ack)"]
    D1 -->|"fix in progress"| D45["Day ~45<br/>CERT/CC default<br/>coordination window"]
    D45 -->|"vendor fixed"| PUB["Coordinated<br/>public disclosure"]
    D45 -->|"vendor silent"| D90["Day ~90<br/>GPa / program<br/>disclosure window"]
    D90 -->|"still silent"| PUB

    D0 -.->|"DON'T"| EARLY["Public disclosure<br/>before fix<br/>(voids safe harbor,<br/>burns goodwill)"]

    style D0 fill:#0d1b2a,stroke:#5eead4,color:#e4e4e8
    style PUB fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style EARLY fill:#2a0d0d,stroke:#a00000,color:#f08080
    style D45 fill:#14141f,stroke:#5eead4,color:#9494a0
    style D90 fill:#14141f,stroke:#5a5a68,color:#9494a0

Reading the diagram: The timeline runs left to right. Day 0: you discover and report privately. Vendor acknowledges and triages within roughly a week. The default CERT/CC coordination window is ~45 days; Google Project Zero and several programs run ~90 days. Public disclosure happens coordinated with the vendor, at or after the window — not before. The red node is the failure mode: early public disclosure voids safe harbor and invites legal action even when the initial finding was authorized. The harness's job is to stamp every finding with report_date, vendor_response, agreed_publication_date — those fields exist so the disclosure timeline is auditable, not improvised.


Diagram 7 — Liability Does Not Transfer to the Model

Type: Mermaid (flowchart, the operator-instrument doctrine) Purpose: The load-bearing point of S00.3, Risk 4. When an autonomous harness exceeds authorization, the liability stays with the operator. Diagrams the controls that follow from accepting this.

flowchart TD
    OP["Operator (you)<br/>deploy · configure · point at target"]
    HARNESS["Autonomous Harness<br/>acts at machine speed"]
    MODEL["Model<br/>reasons, proposes tool calls"]

    OP -->|"deploys + configures scope"| HARNESS
    HARNESS -->|"calls (model is an instrument)"| MODEL
    MODEL -->|"tool proposals"| HARNESS

    HARNESS -.->|"if out-of-scope action"| HARM["§ 1030(a)(2) violation<br/>or CMA s.1 / s.3 offence"]
    HARM -.->|"liability flows to"| OP

    DEFENSE["&quot;the model did it&quot;"]
    DEFENSE -.->.->|"NOT a defense"| X["No court accepts this.<br/>The harness is the operator's instrument."]

    OP -->|"controls that flow from this"| C1["Autonomy ≤ Level 3 in production<br/>(propose → approve → execute)"]
    OP --> C2["Scope enforcement in code<br/>(not the system prompt)"]
    OP --> C3["Audit log: scope_ref per call<br/>(Diagram 2)"]
    OP --> C4["Kill switch + bounded blast radius"]

    style OP fill:#0d1b2a,stroke:#5eead4,color:#e4e4e8
    style HARNESS fill:#14141f,stroke:#5a5a68,color:#e4e4e8
    style MODEL fill:#101018,stroke:#5a5a68,color:#9494a0
    style HARM fill:#2a0d0d,stroke:#a00000,color:#f08080
    style DEFENSE fill:#2a0d0d,stroke:#a00000,color:#f08080
    style X fill:#2a0d0d,stroke:#a00000,color:#f08080
    style C1 fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style C2 fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style C3 fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style C4 fill:#0d2818,stroke:#1e8449,color:#82e0aa

Reading the diagram: Top — the operator deploys and configures the harness; the harness calls the model as one of its instruments; the model proposes actions. The red path: if the harness acts out of scope, the violation occurs and liability flows up to the operator. The lower-right "the model did it" is explicitly marked as not a defense. The four green controls at the bottom are what acceptance of this doctrine requires you to build: bounded autonomy in production, scope enforcement in code, an audit log that reconstructs authorization per call, and a kill switch with bounded blast radius. None of these are optional. Together they are the difference between a defensible engagement and an indictment.

# Diagrams — Module S00: Legal, Ethics, and Rules of Engagement

> All Mermaid validated in Mermaid Live Editor. n8n JSON is structurally valid and importable.

---

## Diagram 1 — The Authorization Chain (and where it breaks)

**Type**: Mermaid (flowchart with break annotations)
**Purpose**: The central visual of S00.1. Authorization is a *chain* from asset owner to atomic tool call. A break anywhere voids downstream cover. Three named breaks correspond to the three failure modes in the teaching doc.

```mermaid
flowchart TD
    OWNER["Asset Owner<br/>owns the system under test"]
    SPONSOR["Program / Engagement Sponsor<br/>operates the bounty or pentest"]
    POLICY["Program Policy / SOW<br/>scope · RoE · safe harbor · evidence rules"]
    SCOPE["Scope File (JSON)<br/>machine-checkable boundary"]
    MW["Scope Enforcement Middleware<br/>intercepts every outbound call"]
    CALL["Tool Call<br/>nmap · http · ffuf · exploit"]

    OWNER -->|chain of title| SPONSOR
    SPONSOR -->|warrants owner auth| POLICY
    POLICY -->|formalized| SCOPE
    SCOPE -->|loaded into| MW
    MW -->|permits only if in-scope| CALL

    BREAK1(("BREAK 1<br/>Sponsor ≠ Owner"))
    BREAK2(("BREAK 2<br/>Action outside RoE"))
    BREAK3(("BREAK 3<br/>Stale scope"))

    BREAK1 -.voids.-> SPONSOR
    BREAK2 -.voids.-> MW
    BREAK3 -.voids.-> SCOPE

    style OWNER fill:#0d1b2a,stroke:#5eead4,color:#e4e4e8
    style SPONSOR fill:#101018,stroke:#5a5a68,color:#e4e4e8
    style POLICY fill:#101018,stroke:#5a5a68,color:#e4e4e8
    style SCOPE fill:#14141f,stroke:#5eead4,color:#e4e4e8
    style MW fill:#14141f,stroke:#5eead4,color:#5eead4
    style CALL fill:#101018,stroke:#5a5a68,color:#9494a0
    style BREAK1 fill:#2a0d0d,stroke:#a00000,color:#f08080
    style BREAK2 fill:#2a0d0d,stroke:#a00000,color:#f08080
    style BREAK3 fill:#2a0d0d,stroke:#a00000,color:#f08080
```

**Reading the diagram**: Read top-down. Each arrow is a link in the chain — and the *only* place legal cover is created is at the top (the asset owner's consent). The three red BREAK nodes are where the chain voids in practice. Break 1: a program operator that doesn't actually hold the owner's authorization. Break 2: an action the RoE forbids, even on an in-scope host. Break 3: a scope file that was valid last week but whose targets were since removed. The scope enforcement middleware (teal) is the engineering realization of the chain — it converts "is this call authorized?" into a binary, code-level check.

---

## Diagram 2 — Scope Enforcement as Harness Middleware (n8n)

**Type**: n8n workflow (importable JSON)
**Purpose**: The primary visual per the course tech stack (n8n first). Shows scope enforcement as a middleware node that sits between the agent's tool request and the network — the load-bearing architectural pattern of S01.2, previewed here in its legal-control framing.

```json
{
  "name": "S00 — Scope Enforcement Middleware",
  "nodes": [
    {
      "parameters": {},
      "name": "Tool Request",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [240, 300],
      "notes": "Agent (or sub-agent) emits a tool_use: {tool, target, action}"
    },
    {
      "parameters": {
        "dataType": "string",
        "value1": "={{ $json.target }}",
        "rules": {
          "rules": [
            { "value2": "={{ $env.SCOPE_IN_SCOPE.split(',') }}", "operation": "isInList" }
          ]
        }
      },
      "name": "Target in Scope?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1.1,
      "position": [460, 300],
      "notes": "Check target against scope.in_scope[]. Match is exact, not glob."
    },
    {
      "parameters": {
        "dataType": "string",
        "value1": "={{ $json.action }}",
        "rules": {
          "rules": [
            { "value2": "={{ $env.ROE_FORBIDDEN.split(',') }}", "operation": "notInList" }
          ]
        }
      },
      "name": "Action under RoE?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1.1,
      "position": [680, 300],
      "notes": "Check action against rules_of_engagement.forbidden[]. e.g. 'dos','exfil','socialeng'"
    },
    {
      "parameters": {
        "dataType": "dateTime",
        "value1": "={{ $now.toISO() }}",
        "rules": {
          "rules": [
            { "value2": "={{ $env.SCOPE_VALID_UNTIL }}", "operation": "before" }
          ]
        }
      },
      "name": "Scope Fresh?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1.1,
      "position": [900, 300],
      "notes": "Reject if scope.valid_until has passed. Prevents stale-scope drift (Break 3)."
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            { "name": "scope_ref", "value": "={{ $json.target }}::{{ $json.action }}::{{ $now.toISO() }}" }
          ]
        }
      },
      "name": "Stamp scope_ref",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [1120, 240],
      "notes": "Annotate the call with the scope entry that authorized it. This is the legal anchor in the evidence log."
    },
    {
      "parameters": {},
      "name": "Execute Tool",
      "type": "n8n-nodes-base.executeCommand",
      "typeVersion": 1,
      "position": [1320, 240],
      "notes": "Only reached if all three checks pass. The network call happens here."
    },
    {
      "parameters": {
        "values": {
          "string": [
            { "name": "blocked_reason", "value": "out_of_scope" }
          ]
        }
      },
      "name": "Block + Log",
      "type": "n8n-nodes-base.set",
      "typeVersion": 2,
      "position": [1120, 360],
      "notes": "Blocked call. Logged with reason. Never reaches the network. This is the legal control."
    }
  ],
  "connections": {
    "Tool Request": { "main": [[{ "node": "Target in Scope?", "type": "main", "index": 0 }]] },
    "Target in Scope?": { "main": [[{ "node": "Action under RoE?", "type": "main", "index": 0 }], [{ "node": "Block + Log", "type": "main", "index": 0 }]] },
    "Action under RoE?": { "main": [[{ "node": "Scope Fresh?", "type": "main", "index": 0 }], [{ "node": "Block + Log", "type": "main", "index": 0 }]] },
    "Scope Fresh?": { "main": [[{ "node": "Stamp scope_ref", "type": "main", "index": 0 }], [{ "node": "Block + Log", "type": "main", "index": 0 }]] },
    "Stamp scope_ref": { "main": [[{ "node": "Execute Tool", "type": "main", "index": 0 }]] }
  }
}
```

**Reading the diagram**: A tool request enters from the agent. Three sequential IF gates — target in scope, action permitted by RoE, scope not stale — each can divert to Block+Log. Only a request passing all three reaches the network. The `scope_ref` stamp is the legal anchor: it records *which scope entry* authorized *this call* at *this time*, producing the "authorization chain to the atom" that protects the operator if the call is ever questioned. This is the n8n shape of the pattern S01.2 implements in code.

---

## Diagram 3 — The Gates-Down Model (post-Van Buren CFAA authorization)

**Type**: Mermaid (statechart)
**Purpose**: Makes the *Van Buren v. United States* (2021) ruling concrete. Authorization is assessed at the "gate" (the file/folder/host boundary), not at the motive layer. A harness must treat each gate as binary.

```mermaid
stateDiagram-v2
    [*] --> Unauth: target never authorized
    [*] --> Auth: scope file permits target

    Unauth --> VIOLATION: any access
    note right of VIOLATION
        § 1030(a)(2): access without authorization.
        Van Buren offers NO shelter here.
        The gate was never opened.
    end note

    Auth --> AuthorizedArea: access permitted file/host
    Auth --> Exceeded: access file/host NOT in scope
    note right of Exceeded
        "Exceeds authorized access" (post-Van Buren):
        accessing an area you are NOT authorized
        to access at all. Not a motive question.
    end note

    AuthorizedArea --> OK: used for security testing
    AuthorizedArea --> STILL_OK: used for improper purpose
    note left of STILL_OK
        Van Buren: improper purpose on an
        authorized area is NOT a CFAA (a)(2)
        violation. Gates-down, not motives-down.
    end note

    Exceeded --> VIOLATION
    OK --> [*]
    STILL_OK --> [*]
    VIOLATION --> [*]
```

**Reading the diagram**: Two entry states — the target is either in your scope file (Auth) or not (Unauth). From Auth, you either stay in an authorized area or exceed into one you were never granted. The *Van Buren* holding is the lower-left: improper purpose on an *authorized* area is not an (a)(2) violation — that is the narrowing. The critical warning for harness builders is the right side: "exceeds authorized access" still cleanly captures reaching an area the scope file never permitted. The narrowing moved the motive inquiry; it did not move the gate. Build the gate (scope enforcement), not a motive detector.

---

## Diagram 4 — When Scanning Becomes DoS (effect-based, not rate-based)

**Type**: Mermaid (flowchart with threshold)
**Purpose**: The CFAA § 1030(a)(5) / CMA s.3 risk model. There is no bright-line request rate. The threshold is *effect on the target*. Shows the harness's required reaction to distress signals.

```mermaid
flowchart LR
    subgraph SCAN["Scanner at rate R"]
        S1["Outbound requests"]
    end

    S1 --> T1{"Target showing<br/>distress?"}
    T1 -->|"5xx spike"| DISTRESS
    T1 -->|"conn resets"| DISTRESS
    T1 -->|"latency spike"| DISTRESS
    T1 -->|"rate-limit hit"| DISTRESS
    T1 -->|"none"| CONTINUE

    DISTRESS["Distress signal<br/>detected"]
    CONTINUE["Continue at R"]

    DISTRESS --> REACT{"Harness reaction"}
    REACT -->|"back off (R/2)"| SCAN
    REACT -->|"threshold exceeded"| HALT

    HALT["STOP — stop condition<br/>this is a CFAA (a)(5) mitigation,<br/>not a performance tweak"]

    style DISTRESS fill:#2a1810,stroke:#a04000,color:#f0a868
    style HALT fill:#2a0d0d,stroke:#a00000,color:#f08080
    style SCAN fill:#0d1b2a,stroke:#1b4f72,color:#e4e4e8
    style CONTINUE fill:#0d2818,stroke:#1e8449,color:#82e0aa
```

**Reading the diagram**: The threshold between "scanning" and "DoS" is the target's distress, not your request rate. A scanner at 5 req/s that takes down a fragile target is a DoS; a scanner at 500 req/s against a hardened one may be fine. The harness cannot know in advance which is which — so it must *react* to distress signals (5xx spikes, connection resets, latency degradation, rate-limit responses) by backing off, and halt entirely if distress persists. That halt is a stop condition (Course 1, Module 1.2) and its legal function is a § 1030(a)(5) mitigation. Default to low concurrency; back off on distress; treat persistent distress as a hard stop.

---

## Diagram 5 — The Evidence Record and its Retention Lifecycle

**Type**: Mermaid (flowchart + statechart hybrid)
**Purpose**: S00.2's two-sided evidence obligation. A finding record has a lifecycle: capture → classify → retain or destroy. The classification determines the retention. Over-retention is as much a liability as under-retention.

```mermaid
flowchart TD
    FIND["Finding detected"]
    CAP["Capture minimum proof<br/>COUNT(*) or 1 redacted row<br/>NOT SELECT *"]

    CAP --> CLASS{"Classify"}

    CLASS -->|"no sensitive data"| PUB["Public"]
    CLASS -->|"redacted at capture"| RED["Redacted"]
    CLASS -->|"real PII / credentials"| REST["Restricted"]

    PUB --> KEEP1["Retain indefinitely<br/>(portfolio artifact)"]
    RED --> KEEP2["Retain for engagement<br/>+ contractual tail"]
    REST --> DESTROY["Destroy on report<br/>or per contract<br/>(whichever sooner)"]

    KEEP1 --> LOG["Evidence store<br/>(append-only, scope-referenced)"]
    KEEP2 --> LOG
    DESTROY --> DELETED["Documented destruction<br/>(record the deletion, not the data)"]

    LOG --> REPORT["Ties finding to scope_ref<br/>from Diagram 2"]

    style CAP fill:#0d1b2a,stroke:#1b4f72,color:#e4e4e8
    style DESTROY fill:#2a0d0d,stroke:#a00000,color:#f08080
    style DELETED fill:#101018,stroke:#5a5a68,color:#9494a0
    style REST fill:#2a1810,stroke:#a04000,color:#f0a868
    style LOG fill:#14141f,stroke:#5eead4,color:#5eead4
```

**Reading the diagram**: Capture is the first decision point — and it is *minimum* proof, by default. The classification gate routes each record to a retention class. Public records can live forever as portfolio artifacts; Redacted records survive the engagement plus a tail; Restricted records (real PII, credentials) are *destroyed on report submission*. The destruction is itself recorded (you keep the record of the deletion, not the deleted data). The evidence store at the bottom is the same append-only, scope-referenced log from Diagram 2 — every record carries the `scope_ref` that authorized the call that produced it. An evidence store that captures everything and destroys nothing has built a compliance time bomb, not an evidence chain.

---

## Diagram 6 — Coordinated Vulnerability Disclosure Timeline

**Type**: Mermaid (sequence/gantt-style flow)
**Purpose**: The CVD baseline. The harness must *emit* disclosure metadata (report date, vendor response, agreed publication date) as part of every finding — this diagram shows why those fields exist.

```mermaid
flowchart LR
    D0["Day 0<br/>Discovery +<br/>private report"]
    D0 -->|"vendor ack"| D1["Day 1–7<br/>Vendor triage<br/>(expected ack)"]
    D1 -->|"fix in progress"| D45["Day ~45<br/>CERT/CC default<br/>coordination window"]
    D45 -->|"vendor fixed"| PUB["Coordinated<br/>public disclosure"]
    D45 -->|"vendor silent"| D90["Day ~90<br/>GPa / program<br/>disclosure window"]
    D90 -->|"still silent"| PUB

    D0 -.->|"DON'T"| EARLY["Public disclosure<br/>before fix<br/>(voids safe harbor,<br/>burns goodwill)"]

    style D0 fill:#0d1b2a,stroke:#5eead4,color:#e4e4e8
    style PUB fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style EARLY fill:#2a0d0d,stroke:#a00000,color:#f08080
    style D45 fill:#14141f,stroke:#5eead4,color:#9494a0
    style D90 fill:#14141f,stroke:#5a5a68,color:#9494a0
```

**Reading the diagram**: The timeline runs left to right. Day 0: you discover and report privately. Vendor acknowledges and triages within roughly a week. The default CERT/CC coordination window is ~45 days; Google Project Zero and several programs run ~90 days. Public disclosure happens *coordinated with the vendor*, at or after the window — not before. The red node is the failure mode: early public disclosure voids safe harbor and invites legal action even when the initial finding was authorized. The harness's job is to stamp every finding with `report_date`, `vendor_response`, `agreed_publication_date` — those fields exist so the disclosure timeline is auditable, not improvised.

---

## Diagram 7 — Liability Does Not Transfer to the Model

**Type**: Mermaid (flowchart, the operator-instrument doctrine)
**Purpose**: The load-bearing point of S00.3, Risk 4. When an autonomous harness exceeds authorization, the liability stays with the operator. Diagrams the controls that follow from accepting this.

```mermaid
flowchart TD
    OP["Operator (you)<br/>deploy · configure · point at target"]
    HARNESS["Autonomous Harness<br/>acts at machine speed"]
    MODEL["Model<br/>reasons, proposes tool calls"]

    OP -->|"deploys + configures scope"| HARNESS
    HARNESS -->|"calls (model is an instrument)"| MODEL
    MODEL -->|"tool proposals"| HARNESS

    HARNESS -.->|"if out-of-scope action"| HARM["§ 1030(a)(2) violation<br/>or CMA s.1 / s.3 offence"]
    HARM -.->|"liability flows to"| OP

    DEFENSE["&quot;the model did it&quot;"]
    DEFENSE -.->.->|"NOT a defense"| X["No court accepts this.<br/>The harness is the operator's instrument."]

    OP -->|"controls that flow from this"| C1["Autonomy ≤ Level 3 in production<br/>(propose → approve → execute)"]
    OP --> C2["Scope enforcement in code<br/>(not the system prompt)"]
    OP --> C3["Audit log: scope_ref per call<br/>(Diagram 2)"]
    OP --> C4["Kill switch + bounded blast radius"]

    style OP fill:#0d1b2a,stroke:#5eead4,color:#e4e4e8
    style HARNESS fill:#14141f,stroke:#5a5a68,color:#e4e4e8
    style MODEL fill:#101018,stroke:#5a5a68,color:#9494a0
    style HARM fill:#2a0d0d,stroke:#a00000,color:#f08080
    style DEFENSE fill:#2a0d0d,stroke:#a00000,color:#f08080
    style X fill:#2a0d0d,stroke:#a00000,color:#f08080
    style C1 fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style C2 fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style C3 fill:#0d2818,stroke:#1e8449,color:#82e0aa
    style C4 fill:#0d2818,stroke:#1e8449,color:#82e0aa
```

**Reading the diagram**: Top — the operator deploys and configures the harness; the harness calls the model as one of its instruments; the model proposes actions. The red path: if the harness acts out of scope, the violation occurs and liability flows *up* to the operator. The lower-right "the model did it" is explicitly marked as not a defense. The four green controls at the bottom are what acceptance of this doctrine *requires* you to build: bounded autonomy in production, scope enforcement in code, an audit log that reconstructs authorization per call, and a kill switch with bounded blast radius. None of these are optional. Together they are the difference between a defensible engagement and an indictment.