# Lab Specification — Module B0: Legal, Ethics, and Disclosure for AI Security Testing

**Course**: Course 2B — Securing & Attacking Harnesses and LLMs
**Module**: B0 — Legal, Ethics, and Disclosure for AI Security Testing
**Duration**: 60–75 minutes
**Environment**: No special tooling. A text editor, a JSON linter, and Python 3.10+ (for the scope-gate function). This lab builds the legal/scope *artifacts* that feed B1's threat-model enforcement — it is mostly document-and-code generation, not execution.

---

## Learning objectives

By the end of this lab you will have:

1. **Read and parsed a real model-provider Acceptable Use Policy** (OpenAI or Anthropic) and extracted the clauses that constrain red-team activity — the ToS layer the deployer cannot waive.
2. **Formalized an AI red-team scope boundary as a JSON scope file** that separates deployer-controlled surfaces from provider-controlled surfaces, with a `provider_authorization` field per technique.
3. **Written an AI-specific CVD timeline template and a dual-use disclosure decision rubric** — the document that governs what you publish vs. withhold when you find a jailbreak.
4. **Built a `provider_authorization_check()` function** that the red-team harness runs before every provider-surface technique — the engineering realization of "the deployer cannot authorize what the provider forbids."

This lab is deliberately low-execution. The point is to build the *governance artifacts and the gate* before any technique from B1 onward is pointed at a target. A red-team without these four artifacts is a red-team operating without a legal control plane.

---

## Phase 0 — Setup (2 min)

```bash
mkdir b0-legal-lab && cd b0-legal-lab
# No dependencies for the core lab. Optionally fetch the provider AUP:
#   OpenAI:  https://openai.com/policies/terms-of-use/
#   Anthropic: https://www.anthropic.com/legal/aup
# Save the text locally; you'll parse clauses from it.
```

No venv, no GPU. This is a governance and code lab.

---

## Phase 1 — Parse the provider Acceptable Use Policy (15 min)

### 1.1 Fetch and read

Choose one provider's current AUP/Terms (OpenAI or Anthropic — or both, for comparison). Read the sections covering:

- **Reverse engineering / model access** — does the ToS prohibit extracting weights, accessing the model "behind" the API, or reverse-engineering?
- **Jailbreaking / misuse** — does it prohibit attempts to bypass safety training or generate disallowed content?
- **Automated access / volume** — are there rate caps or automation restrictions?
- **Data / training opt-out** — does the provider train on API inputs by default? Is there an opt-out?

### 1.2 Extract the constraint clauses

Create `provider_tos_extract.md` and, for each relevant clause, record:

```markdown
## Clause: [short name]
- **Source**: [provider] AUP, [section/URL anchor], retrieved [date]
- **Verbatim**: "[the exact wording]"
- **Techniques constrained**: [jailbreak | weight_read | system_prompt_extract | high_volume | ...]
- **Permitted under**: [explicit permission | preview program | waiver | none]
- **Red-team implication**: [what this means for an engagement against a deployer using this model]
```

Produce at least four clauses (one per category above).

### 1.3 The key judgment

For each clause, answer: **"Can the deployer's authorization override this?"** The answer, in every case where the provider retains the right, is **no**. Record this explicitly — it is the single most important takeaway of Phase 1.

---

## Phase 2 — The AI red-team scope file (20 min)

Build `ai_scope.json` — the machine-checkable boundary that feeds B1's scope enforcement. The schema separates **deployer-controlled** from **provider-controlled** surfaces and carries a `provider_authorization` field per technique.

### 2.1 The schema

```json
{
  "engagement": {
    "client": "[deployer name]",
    "sponsor": "[engagement sponsor]",
    "valid_from": "2026-07-09T00:00:00Z",
    "valid_until": "2026-08-09T00:00:00Z",
    "model_versions_in_scope": ["gpt-4o-2026-05-01", "claude-opus-4-1-20260605"]
  },
  "deployer_surfaces": [
    {
      "id": "system_prompt",
      "type": "config_artifact",
      "data_class": "provider_only",
      "retention": "engagement_plus_90d",
      "techniques": ["read", "extract"]
    },
    {
      "id": "retrieval_store",
      "type": "datastore",
      "data_class": "restricted",
      "retention": "destroy_on_report",
      "techniques": ["query", "read_metadata"]
    },
    {
      "id": "code_exec_tool",
      "type": "tool_surface",
      "data_class": "public",
      "retention": "indefinite",
      "techniques": ["invoke", "abuse_test"]
    }
  ],
  "provider_surfaces": [
    {
      "id": "model_weights",
      "technique": "weight_read",
      "provider_authorization": {
        "tos_permits": false,
        "waiver_on_file": null,
        "self_hosted_owned_by_deployer": false,
        "decision": "BLOCK"
      },
      "minimum_proof": "path + hash + byte_count",
      "retention": "destroy_on_report"
    },
    {
      "id": "base_refusal_layer",
      "technique": "jailbreak",
      "provider_authorization": {
        "tos_permits": false,
        "waiver_on_file": "anthropic-research-enrollment-2026-06",
        "waiver_expires": "2026-12-31T00:00:00Z",
        "self_hosted_owned_by_deployer": false,
        "decision": "ALLOW"
      },
      "measurement": "success_rate_over_N",
      "disclosure_class": "provider_only_recipe"
    }
  ],
  "disclosure": {
    "model_level_embargo_days": 180,
    "harness_level_embargo_days": 90,
    "publish_recipe_by_default": false,
    "withhold_pure_misuse_no_defensive_lesson": true
  }
}
```

### 2.2 Your task

- Fill in the `engagement` block with realistic values (a sample client).
- Add at least three deployer surfaces and at least two provider surfaces.
- For the `provider_surfaces`, set the `provider_authorization.decision` correctly based on the clauses you extracted in Phase 1. At least one must be `BLOCK`.
- Validate the JSON (`python3 -m json.tool ai_scope.json`).

### 2.3 The data-class decision

For each surface, justify the `data_class`:
- `public` — no sensitive data; safe to retain.
- `provider_only` — trade-secret-adjacent (system prompt); share with provider under NDA only.
- `restricted` — may contain PII (retrieval store); destroy on report.
- `destroy_on_report` — working jailbreak prompts; never carry cross-client.

Record your justification in `scope_justification.md`.

---

## Phase 3 — The CVD timeline + dual-use rubric (15 min)

Create `cvd_and_dual_use.md` with two sections.

### 3.1 CVD timeline template

A fill-in template for an AI finding's disclosure lifecycle:

```markdown
# CVD Timeline — [Finding ID]

- **Model version / checkpoint**: [pinned version]
- **Finding type**: [prompt_injection | memory_poisoning | jailbreak | weight_extraction | ...]
- **Surface level**: [model-level | harness-level]

## Timeline
- [date] — Private report to provider (NDA). Recipe shared under NDA.
- [date] — Acknowledgement from provider.
- [date] — Mitigation deployed (guardrail / version bump / harness patch).
- [date] — Residual-risk re-measurement (InjecAgent-style, success rate before/after).
- [date +180d for model-level / +90d for harness-level] — Coordinated public disclosure.

## Public advisory content
- [ ] Existence + severity: YES
- [ ] Success-rate measurement (N/M + sampling params): YES
- [ ] Defensive lesson / technique class: [YES if new | WITHHELD if pure misuse]
- [ ] Working recipe: NO (unless provider consents AND technique is independently well-known)
```

### 3.2 Dual-use decision rubric

A decision tree you run for every finding before any external communication:

```markdown
# Dual-Use Decision Rubric

1. Is the finding reported to the provider under NDA? → MUST be YES before anything else.
2. Does the finding reveal a NEW technique or architectural insight?
   - YES → Publish the TECHNIQUE (not the recipe) after the embargo. This advances defense.
   - NO  → Go to 3.
3. Is the finding pure-misuse-enabling (a recipe with no defensive lesson)?
   - YES → WITHHOLD publication. Provider-only disclosure. (Diverges from "publish everything.")
   - NO  → Publish existence + severity + residual-risk measurement after the embargo.
4. In all cases: never publish the working recipe unless the provider consents AND the
   technique is independently well-known enough that publication adds no marginal misuse risk.
```

Write the rubric in plain language a client's counsel can sign off on.

---

## Phase 4 — The `provider_authorization_check()` gate (15 min)

Implement the function the red-team harness calls before every provider-surface technique. This is the engineering control that prevents the most common AI red-team legal mistake.

### 4.1 The spec

```python
from datetime import datetime, timezone

def provider_authorization_check(technique: str, model_id: str, scope: dict) -> dict:
    """Check whether a provider-surface technique is authorized for a target model.

    Returns {"decision": "ALLOW"|"BLOCK", "reason": str}.
    The deployer's authorization does NOT extend to provider-controlled surfaces;
    the provider's own ToS/waiver/ownership must independently permit the technique.
    """
    # 1. Find the provider_surface entry matching (technique, model_id).
    # 2. Evaluate the three conditions:
    #    a. tos_permits == True
    #    b. waiver_on_file is not None AND not expired (compare to valid_until / waiver_expires)
    #    c. self_hosted_owned_by_deployer == True
    # 3. If any condition is True -> ALLOW (record which).
    # 4. Else -> BLOCK with the reason.
    # 5. Always check engagement.valid_until has not passed; if expired -> BLOCK "scope expired".
    pass
```

### 4.2 Implement it

Fill in the body. Edge cases to handle:
- **Expired scope** — `engagement.valid_until < now` → BLOCK with reason "engagement scope expired; re-verify authorization."
- **Expired waiver** — `waiver_expires < now` → treat `waiver_on_file` as invalid → BLOCK unless another condition holds.
- **Model not in scope** — `model_id` not in `engagement.model_versions_in_scope` → BLOCK "model version not in scope."
- **Unknown technique** — no matching `provider_surface` entry → BLOCK "technique not authorized for any provider surface."

### 4.3 Test cases

Write at least four test calls against your `ai_scope.json`:

```python
# 1. weight_read on a model with no waiver -> BLOCK
# 2. jailbreak on a model with a valid, unexpired waiver -> ALLOW
# 3. jailbreak after the waiver expires -> BLOCK
# 4. any technique after engagement.valid_until -> BLOCK
```

Print the decision + reason for each. All four must produce the correct result.

### 4.4 The point

This function is the legal control made engineering. B1's threat-model scope enforcement calls it before every provider-surface action. A red-team that runs without it is relying on a human to remember the ToS gap — and humans forget exactly when a finding is about to drop.

---

## Phase 5 — Stretch: the evidence-retention classifier (optional, 10 min)

If time remains, write a second function that classifies a captured artifact by data class and assigns its retention rule:

```python
def classify_and_retain(artifact: dict, surface: dict) -> dict:
    """Given a captured artifact and the surface it came from, return its
    data_class, retention rule, and an enforceable destruction deadline."""
    pass
```

The point: classification must be automatic at capture time, not a wiki entry. An evidence logger that writes everything to a permanent directory with no classification is building a compliance violation and a misuse-enabling dataset simultaneously.

---

## Deliverables

- `provider_tos_extract.md` — the clauses that constrain red-team activity (Phase 1)
- `ai_scope.json` — the machine-checkable scope boundary, surfaces separated (Phase 2)
- `scope_justification.md` — data-class justifications (Phase 2)
- `cvd_and_dual_use.md` — CVD timeline template + dual-use rubric (Phase 3)
- `provider_auth.py` — the `provider_authorization_check()` gate + test calls (Phase 4)
- (optional) `evidence_classify.py` — the retention classifier (Phase 5)

## Success criteria

- [ ] At least four provider-ToS clauses extracted, each with the "can the deployer override?" judgment.
- [ ] `ai_scope.json` validates, has ≥3 deployer surfaces and ≥2 provider surfaces, ≥1 BLOCK decision.
- [ ] CVD template distinguishes model-level (180d) from harness-level (90d) embargoes.
- [ ] Dual-use rubric reaches the "withhold pure-misuse, no-defensive-lesson" branch.
- [ ] `provider_authorization_check()` returns the correct ALLOW/BLOCK for all four test cases, including expiry.
- [ ] Every artifact ties back to a specific clause or principle from the teaching document.
