Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/C2.14.mp4The offensive agent is the least supervised and most capable thing in the estate, and its own traffic looks exactly like an attack.
A preflight that refuses to start the engagement until every control is present, and tells the SOC what to expect.
Run the preflight against two engagement configurations and read why one of them cannot start.
The offensive agent is the most capable and least supervised thing in the estate, and its traffic is indistinguishable from an attack by design. The controls go on before it starts, because the absence of most of them is invisible until it has already cost something.
pentest.preflight() returns what is missing and may_start() refuses. Seven controls, each one somebody has skipped "just for this engagement" — including soc_notified, which is the one that turns a finding into a call at 2am, because an offensive agent's traffic is an attack and an unannounced one is indistinguishable from the real thing by design.The preflight an offensive agent starts behind: a gate rather than a checklist, refusing until every control is present — including telling the SOC, because unannounced offensive traffic is indistinguishable from the real thing by design.
The offensive agent is the most capable and least supervised thing in the estate, and its traffic is indistinguishable from an attack by design.
Run a preflight that refuses to start until zero retention, sandboxing, egress control, secret management, human-in-the-loop and deterministic guardrails are all present.
Blocking controls present out of six, and whether the SOC was briefed. The refusal is the deliverable when they are not.
Measure this
| what to measure | denominator or target |
|---|---|
| blocking controls present | count out of six |
| whether the SOC was briefed | yes/no; the refusal is the deliverable when it is no |
before the offensive agent starts if absent [BLOCK] zero data retention target data trains a 3rd party [BLOCK] sandbox an escape lands on a real host [BLOCK] egress allowlist a compromised harness pivots [BLOCK] secret management your creds end up in a trace [BLOCK] human in the loop an exploit hits production [BLOCK] deterministic guardrails the model is argued out of scope [warn ] SOC notified your own team runs a real incident six block because their absence is invisible until it has cost something. the seventh is advisory: you can pick up the phone mid-engagement.
An offensive agent is the most capable and least supervised thing in the estate. It scans, reasons and exploits at machine speed, on credentials you issued, against systems you care about — and its traffic is, by design, indistinguishable from an attack. That combination is why the controls go on before it starts.
Seven controls, and six of them are blocking — the engagement does not begin without them, because each one's absence is invisible until it has already cost something:
The seventh, SOC notification, is advisory — not because it matters less, but because its absence is recoverable: you can pick up the phone mid-engagement. And the brief carries one instruction the SOC skips at its peril — do not mute the rules. An engagement your own detection team suppressed produces a clean report and no evidence anything would have been caught, which was half the reason to run it.
The skill takes two CyberTravels engagement setups and runs both through the preflight.
One is refused, because it is missing controls that block a start, and the skill names each missing control rather than just saying no.
The other may begin, and for that one it prints the brief the SOC needs before anything starts running.
The skill — skills/redteam/offensive-agent-safety-preflight/SKILL.md
name: offensive-agent-safety-preflight
description: >-
Refuse to start an offensive-agent engagement until zero-retention,
sandboxing, egress control, secret management, human-in-the-loop,
deterministic guardrails and SOC notification are in place, and brief the SOC
on what to expect. Use before giving an agent offensive capability.
allowed-tools: Read, Grep, GlobAn offensive agent scans, reasons and exploits at machine speed, on credentials you issued, against systems you care about — and its traffic is, by design, indistinguishable from an attack. That combination is why the controls go on before it starts, not after the first surprise, and why the preflight is a gate rather than a checklist.
Before any engagement where an agent has offensive capability, and before re-running one whose configuration changed.
1 — Check the six blocking controls. Zero data retention, sandboxing, an egress allowlist, secret management, human-in-the-loop on destructive actions, and deterministic guardrails that enforce scope outside the model. Blocking means the engagement does not start without it — because each one's absence is invisible until it has already cost something.
2 — Check the advisory control. SOC notification is advisory only because its absence is recoverable: you can pick up the phone mid-engagement. Nothing else on the list is.
3 — Refuse, with the reason. A missing blocking control stops the engagement and names what it would have prevented. "Looks fine" is not the output; a decision is.
4 — Brief the SOC, and tell them not to mute. Window, source addresses, expected signatures — and the instruction to record what fired and what did not, because measuring detection is half the reason to run the engagement at all.
ENGAGEMENT REFUSED — 4 blocking control(s) missing:
zero_data_retention, egress_allowlist, human_in_the_loop, deterministic_guardrails
The run continues past this. test_skills.py executes the script on every build, with no model configured — so what CI proves is that it runs and refuses legibly, not that it prints these lines. The output above is a recorded run against a real model, and nothing re-diffs it: a model's answer is not reproducible, and this repository does not claim otherwise anywhere it can be checked.
{
"controls": [{"name": "str", "blocking": true, "present": true,
"if_absent": "str"}],
"engagements": [{"name": "str", "may_start": true,
"blocking_missing": ["str"], "advisory_missing": ["str"]}],
"soc_brief": {"window": "str", "sources": "str", "expect": ["str"]}
}
Three ways to do this lesson. Pick one. They run the same procedure against the same code — what changes is who drives it, and how much you see.
The agent reads the lesson, explains the idea, fetches the code, runs the check and answers your questions as you go. This is the one to take if you are here to learn.
Install it, once. From the folder you cloned. --all does every agent it finds on your machine:
python3 scripts/install_skills.py --all --lessons C2.14Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick c2-14-bonus:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons C2.14 | type /c2-14-bonus |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons C2.14 | type /c2-14-bonus in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons C2.14 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons C2.14 | type $c2-14-bonus, or run /skills |
No agent, no conversation. The same lesson executes and prints the same readback. Take this one if you have no assistant, if you are reviewing rather than learning, or if you want the result without the teaching around it.
python3 scripts/lesson.py C2.14Neither of the above, and no model needed. The first command writes CyberTravels exactly as it stood at the end of this lesson; the second prints the diff — the lines this lesson added or changed, and nothing from any later one.
python3 scripts/checkpoint.py --at C2.14 --out work/cybertravels
python3 scripts/checkpoint.py --at C2.14 --diffOn Windows, type python wherever these say python3 — and use \ instead of / in the paths. Everything else is identical. A0.0 step 2 explains why.
Ways 1 and 2 need a model; way 3 does not. A signed-in Claude Code CLI needs no API key, and any OpenAI-compatible endpoint works too. With neither, the audit exits 2 and says so rather than inventing an answer. A0.0 sets this up.
Ways 1 and 2 both end with the same readback: What I did, What changed, The number and Read this next. A step that was skipped or refused is reported as exactly that, never as a pass.
If you did the last lesson’s challenge, expect this to stop. Most challenges ask you to edit the code, and ways 1 and 2 will not overwrite your edits: you get stopped, not a failure, with two options — --out for a fresh folder that keeps your work, or --force to discard it and start this lesson clean.
The quick-look configuration is refused with four blocking controls named — zero retention, egress allowlist, human in the loop and deterministic guardrails — while the fully configured engagement is cleared and produces a SOC brief with its window, source addresses and expected signatures, ending on the instruction not to mute.
Write your own engagement scope as a structure the harness reads, not a paragraph in a PDF, and run this preflight against it. The control you cannot currently satisfy is the one to fix before the next engagement, not after it.
Skill source: skills/redteam/offensive-agent-safety-preflight