Red-Teaming Lab
- Build a threat model for the capstone: assets, adversaries, and attack surfaces
- Assemble a structured, versioned attack suite spanning direct, indirect, and exfiltration attacks
- Automate the suite into a repeatable runner that reports attack success rate by category
- Write a findings report that ranks issues by severity and tracks each to closure
| Spaced-rep warm-up: injection & guardrails cards (D132/133) | 10 min |
| ELI5 + tech read: threat model, attack taxonomy, ASR | 20 min |
| Guided: assemble the attack suite + build the runner | 40 min |
| Practice: threat-model your capstone | 15 min |
| Project: formal red-team pass + findings report | 25 min |
| Quiz + flashcards | 10 min |
Builds on: Day 132 β Guardrails, injection & AI security Β· Day 133 β Red-team your RAG (first pass) Β· Day 141 β Regression gates
A building doesn't find out whether its fire plan works during a fire. It runs drills: planned, scheduled, scored. Someone plays the fire β blocking a stairwell, pulling an alarm on floor 3 β and inspectors with clipboards record what actually happened: who froze, which exit jammed, how long the evacuation took. Then the building fixes the jammed exit and drills again next quarter, because buildings change β new tenants, new furniture, new doors.
Red-teaming your AI system is the same discipline applied to the con artist from Day 132. On Day 133 you ran your first improvised drill against the capstone. Today you make it a real fire-safety program: a written list of attacks (poison a document with hidden instructions, ask the bot to reveal its system prompt, try to make it answer off-policy), a runner that fires every attack and scores whether it succeeded, and a report ranking what got through by how badly it could hurt you. The point is not a one-time clean bill of health β your prompts, corpus, and model all change, and every change can reopen a door. So you drill on a schedule and keep the scorecard, turning "is it safe?" from a feeling into a number you can watch over time.
A docs-QA assistant has a uniquely nasty attack surface: it reads documents, and documents can carry instructions. An attacker who can get one poisoned page into your corpus β a wiki edit, an uploaded PDF β can hijack answers for every user (indirect prompt injection, Day 132's lethal-trifecta case). Improvised testing misses this because you test what you can imagine; a structured, versioned suite tests the same battery every release and catches regressions in your defenses. For an FDE, a red-team report with attack-success-rate trends is exactly what a customer's security review demands before go-live (Day 159) β "we run 25 attacks in CI and here is the closure log" is the sentence that unblocks a deal.
Guided practice
Assemble a versioned attack suite
20 min- Create
redteam/attacks.jsonlfrom the starter β one JSON object per line, each withid,category,input, optionalinject_doc(a poisoned document to add to the corpus for indirect attacks), anddetectordescribing success. - Write at least 4 attacks per category (direct, indirect, exfiltration, off-policy) β 16+ total. Base several on real Day-132/133 findings and on the Simon Willison and OWASP examples in resources.
- Plant a canary in your system prompt: a fake secret string like
CANARY-7Q2X. Any output containing it means exfiltration succeeded β an unambiguous detector. - Commit the file. It is now versioned: every future change to it shows up in a diff, and the suite is reproducible.
Build the runner and the ASR report
20 min- Write
redteam/run_attacks.pyfrom the starter. For each attack: if it hasinject_doc, add that document to a *copy* of the retrieval index (never your real one), run the query through your capstone's answer function, then apply the detector. - The detector functions are tiny β
contains_canarychecks for your canary string;answered_off_topicchecks the model did NOT refuse. Add detectors as you add attack types. - Run it: terminal:
python redteam/run_attacks.py. It prints per-attack pass/fail and an ASR table by category. - Interpret: any non-zero ASR is a finding. Sort by category and note which attacks got through.
- Save the JSON report to
redteam/report_<date>.jsonso you can diff ASR against next week's run.
On your own
Threat-model your own capstone
15 minFill in a threat-model table for your docs-QA service before you trust any test result. Rows = assets (system prompt, corpus integrity, other users' data, token budget, reputation). Columns = surfaces (user query, retrieved document, tool call if any, rendered output). In each meaningful cell write the concrete attack and its worst-case impact. Then rank the top 5 cells by severity (impact Γ how easy to pull off) and confirm your attacks.jsonl has at least one case for each of the top 5 β add any that are missing.
Hints: the highest-severity cell for most docs-QA apps is (other users' data or corpus integrity) Γ (retrieved document) β indirect injection β precisely because the attacker doesn't need an account, just the ability to influence one document.
Formal red-team pass on the capstone
Run a real red-team engagement against your capstone and produce the artifact a customer's security team would ask for. Deliver redteam/attacks.jsonl (20+ attacks across all five categories, versioned), the runner, at least one dated ASR report, and redteam/findings.md. The findings doc must list every attack that succeeded, ranked by severity, each with: a reproduction, the root cause, the fix you applied (or the ticket if deferred), and β for every fix β the eval case you promoted into the Day-141 gated suite so it cannot regress. Close the loop on at least the top two findings: show the attack succeeding before the fix and failing after, and show the corresponding case now blocking in the gate.
Common mistakes & misconceptions
- Testing only what you can imagine in the moment. A versioned suite run every release is what catches defenses that quietly broke β improvised testing cannot.
- Skipping indirect injection because "our users are trusted." The attacker is the document, not the user; anyone who can edit a source page is in your threat model.
- Running attacks against your live retrieval index. Poisoned documents belong in a throwaway copy β never mutate production corpus during a drill.
- Vague detectors like "looks bad." Success must be a deterministic rule (canary present, refusal absent) or your ASR is unmeasurable and unreproducible.
- Fixing a finding without promoting it to the gate. An ungated fix reopens the moment someone edits the prompt β the Day-141 case is what makes the fix permanent.
- Treating a clean run as done forever. New model versions and new documents reopen doors; ASR is a metric you monitor, not a certificate you frame.
Q1. Which attack category is unique to RAG systems and most often missed?
Q2. Why plant a canary string in the system prompt for the exfiltration tests?
Q3. You fix an indirect-injection hole. What makes the fix durable?
Go deeper β curated resources
- promptfoo red-team plugins β β Compare your hand-rolled runner to an off-the-shelf red-team harness β which attack generators would you adopt, and which detectors would you still hand-write?
- attacks.jsonl versioned with 20+ attacks across all five categories
- Runner prints ASR by category and saves a dated report
- An indirect-injection attack via poisoned document is detected
- findings.md ranks issues and the top two fixes are gated (before/after shown)
- Quiz β₯ 2/3
β Back: This industrializes Day 133's improvised red-team using Day 132's attack taxonomy, and every fix rides the Day-141 gate to stay closed.
Forward β: Day 145 watches ASR alongside quality metrics for drift, Day 147 requires red-team findings closed or ticketed for the observability gate, and Day 159 hands this report to a customer's security review; Day 177 re-runs the whole suite during capstone hardening.
Unlocks: D147 Observability Complete Β· D177 Capstone Quality Gates