Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/E2.2.mp4Scope drift, unusual tool sequencing, off-hours autonomous action.
Detections whose subject is a non-human principal.
Write five detections for agent misbehaviour and fire each one.
Writing a detection for an agent means writing one where machine-speed behaviour is normal and the baseline has no human rhythm in it at all. Every heuristic that relies on tiredness, working hours or typing speed is gone.
lookup_vendor_doc then issue_refund is the Northwind notice working — an action with no human in its chain, and an approval granted faster than the content could be read.Detections whose subject is a non-human principal, mapped to ATT&CK and ATLAS, and written about relationships rather than volumes: a widened scope, an unseen tool pair, an action with no human behind it, an approval faster than reading.
Classic baselines call two countries in an hour an incident and 300 file reads a minute an incident; for an agent both are ordinary.
Detect change rather than activity — a tool never used before, a shifted mix, a scope newly exercised — and map each to ATT&CK and ATLAS.
Rules carrying a technique id, and the honest gap: indirect prompt injection has no ATT&CK technique, and mapping it to an adjacent one to complete a chart is how a programme lies to itself.
Measure this
| what to measure | denominator or target |
|---|---|
| rules carrying a technique id | share of rules |
| techniques with no honest mapping | count — indirect prompt injection has none, and inventing one is how a programme lies to itself |
human baseline agent baseline +-------------------+ +----------------------+ | works 9-6 | | works always | | 12 actions/hour | | 1400 actions/hour | | makes typos | | never retries a typo | +-------------------+ +----------------------+ detect on SHAPE, not volume: new resource classes, new tool sequences, a spike in distinct destinations
This is the new work, and it starts by discarding baselines that have served the SOC well for twenty years.
Human behavioural detection assumes irregularity, working hours, and a rate ceiling set by typing speed. An agent violates all three while behaving correctly:
| Classic signal | For a human | For an agent |
|---|---|---|
| two countries in an hour | incident | routine (multi-region) |
| 300 file reads a minute | incident | idle |
| activity at 03:00 | suspicious | meaningless |
| the same action 500 times | suspicious | a stuck loop — but not malicious |
Applying human baselines to agents produces an alert on every session, so the rule gets tuned down, and then it never fires again — including when something is genuinely wrong.
The signals that do work for agents are about change: a tool it has never used, a mix that has shifted, a scope exercised that was never needed before.
A rule with no technique against it cannot be gap-analysed, cannot be handed to another team, and cannot be argued about with an auditor. Two matrices are needed and they are not interchangeable: ATT&CK describes what the actor did to your estate, ATLAS describes what was done to the model.
| agent signal | ATT&CK | ATLAS tactic |
|---|---|---|
| a tool it has never used, on inherited credentials | T1078 Valid Accounts | ML Attack Staging |
| bulk reads across a repository it has no task in | T1213 Data from Information Repositories | Exfiltration |
| output posted to an allowed SaaS domain | T1567 Exfiltration Over Web Service | Exfiltration |
| shell spawned from a model-produced string | T1059 Command and Scripting Interpreter | ML Attack Staging |
| instruction arriving in retrieved content | — | Initial Access · AML.T0051 |
Read the last row twice. Indirect prompt injection has no ATT&CK technique, because ATT&CK has no notion of an instruction channel that is also a data channel. Mapping it to something adjacent to make the coverage chart look complete is the single most common way an agent detection programme lies to itself.
ATLAS technique identifiers move faster than ATT&CK's, so re-check any specific AML.T#### against the live matrix before you put it in a report.
Anchor → E1.0. This is the detect interval for the agent itself, and the classic baselines leave it at infinity. Two countries in an hour is an incident for a person and multi-region routine for an agent; three hundred file reads a minute is an incident for a person and idle for an agent; 03:00 is suspicious for a person and meaningless for an agent.
"Anomaly detected" fails both tests: it does not say what changed, and it does not say what to do.
All three classic rules fire on CyberTravels' patch agent doing exactly its job, and only the rate rule fires on the human. The skill runs both, then measures drift from a signed-off baseline week by week — naming the new tool rather than reporting a distance.
The skill — skills/detection/agent-aware-rule-review/SKILL.md
name: agent-aware-rule-review
description: >-
Run existing detection rules against an agent doing its job to find which fire
on legitimate work, and measure behavioural drift from a signed-off baseline
week by week. Use when agents enter an estate whose detection content predates
them.
allowed-tools: Read, Grep, GlobDetection content written for humans classifies agent behaviour as an incident: the volume rule, the off-hours rule, the breadth-of-access rule. Turning them off loses coverage; leaving them on trains the analyst to ignore them. The answer is a per-population baseline and a drift measure against it.
Whenever agents are introduced into an estate with existing detection content, and at each model or manifest upgrade afterwards.
1 — Run each classic rule against a clean agent run and against a human's day. Record which fire on which. Rules that fire on the agent and not the human are the ones needing a population.
2 — Sign off a baseline for each agent. Tools used, resources touched, rate, hours. Signed off means somebody agreed it — a baseline nobody approved is a measurement, not a control.
3 — Compare each subsequent week against the baseline. Report a drift figure and, more usefully, the new items: a tool that was not in the baseline is the signal, and it is legible in a way a distance number is not.
4 — Set a tolerance and say what crossing it does. Drift within tolerance is noise; beyond it is a review, and the review is of the change that caused it — usually a model upgrade or a manifest edit.
5 — Write the alert text for a human. "patch-agent drift 0.35, new tools: run_shell" is actionable. A distance metric on its own gets closed.
Input — the fixture committed at the top of scripts/agent_aware_rule_review.py. Edit it and re-run: the buckets, counts and verdicts below are derived from it, not hard-coded.
Output — the opening lines of a real run:
classic rule fires on agent fires on human
------------------------------------------------------------------
rate > 30 actions/min True False
activity outside 09:00-18:00 True True
same action > 100 times True False
All three fire on an agent doing exactly its job. Deployed as-is, they
produce continuous noise and are disabled within a week.
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.
{
"classic_rules": [{"name": "str", "fires_on_agent": true, "fires_on_human": false}],
"baseline": {"agent": "str", "tools": ["str"], "resources": ["str"], "signed_off": true},
"weeks": [{"week": 0, "drift": 0.0, "new_tools": ["str"], "within_tolerance": true}],
"tolerance": 0.0,
"alert_text": "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 E2.2Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick e2-2-detections-whose-subject-is-the-agent:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons E2.2 | type /e2-2-detections-whose-subject-is-the-agent |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons E2.2 | type /e2-2-detections-whose-subject-is-the-agent in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons E2.2 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons E2.2 | type $e2-2-detections-whose-subject-is-the-agent, 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 E2.2Neither 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 E2.2 --out work/cybertravels
python3 scripts/checkpoint.py --at E2.2 --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.
All three classic rules fire on an agent doing its job and only the rate rule fires on the human. Drift is within tolerance at week 1, significant at week 4 with write_file and repo:write new, and larger at week 8 with run_shell and an exec scope. The alert text names what changed, why it matters and what to do.
Take one human-baseline rule in your SIEM and check how it behaves against a service account. If it fires nightly, it is already tuned off for that actor — which means you have no detection there at all.
Tools used
Skill source: skills/detection/agent-aware-rule-review