All lessons › Function D — Agentic Evaluation and Red Teaming › One Red-Team Lifecycle, End to End
D1.8

Defensive deception and threshold failures

D1
▶
Lightboard recording

Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.

Video placeholderpublishes automatically from recordings/D1.8.mp4

The lab

Place canaries outside every legitimate path, and flag the one sited close enough to real work to fire on it.

◉Use case relevance

Every detector in this function needed a threshold, and every threshold is a trade. A canary in the index needs neither — nothing legitimate has any reason to touch it — until the canary is placed where real work does.

At CyberTravels. redteam/deception.py will not place a canary without the reason nothing legitimately reads it, written down. Four placements in your tree, each with that second column earned. Then the failure the lesson exists for: a canary alert has a count of one by construction, and suppressed_by_threshold() shows a volume rule tuned to five swallowing the one alert that needed no triage.

◴What this lesson is — Day 0, Day 1, Day 2

Deception as the one alert with no triage step, and the placement rule that keeps it that way — if you cannot name why nothing reads it, it is not a canary. Plus the two things canary write-ups skip: decay, and a volume threshold that swallows the conclusive alert.

Day 0 — why

Every other detector needs a threshold, and every threshold trades misses against false alarms.

Day 1 — how

Place canary tokens and honeypot tasks where no legitimate task reaches, so a touch needs no threshold at all.

Day 2 — measure

False-positive rate of zero by construction — and the count of canaries that legitimate work does reach, which breaks that property.

Measure this

what to measuredenominator or target
false-positive rate of the canarieszero by construction
canaries legitimate work reachescount; each one breaks that property

▦The framework, and how it works

   every other detector          deception

   signal -> threshold -> alert  canary token in the index
             (a trade)                   |
                                   nothing legitimate reads it
                                         |
                                   one touch = alert, FP rate 0
   failure: a canary placed where real work reaches it, which
   converts a zero-FP control back into a tuned one

Every detector in this function has needed a threshold, and every threshold is a trade. Deception is the exception: a canary token or a honeypot task in a data index has a false-positive rate of zero by construction, because nothing legitimate has any reason to touch it.

Defensive deception means placing weaponised values — tokens that look genuine, files no real task references — where a data-harvesting agent would plausibly reach, so the alert needs no threshold at all. The failure mode is a canary that legitimate work does touch, which converts a zero-false-positive control back into a tuned one.

2 · Demo — a canary in the index, and a zero-threshold alert

3 · Where it breaks — the canary something legitimate reads

4 · The control — bait nothing legitimate has a reason to touch

5 · The procedure, as a skill

Two words first. A canary token is a credential that looks real and that nothing legitimate ever uses. A honeypot task is a job nobody should take.

The skill places both in CyberTravels' environment. Then it checks something important: that no normal, honest path reaches either of them.

That check is what makes the alert worth having. If nothing legitimate can touch it, a touch cannot be a false alarm. There is no innocent explanation left to rule out.

▶Real time execution as skill

The skill — skills/detection/canary-and-honeypot-design/SKILL.md

name: canary-and-honeypot-design
description: >-
  Place credential canaries and honeypot tasks in an agent's environment so that
  an alert has no structurally possible false positive, and measure how fast the
  signal decays as agents learn. Use when deception is being added, or when a
  detection needs to be one nobody has to triage.
allowed-tools: Read, Grep, Glob

An alert with no possible false positive

A canary credential that nothing legitimate uses produces an alert that needs no triage: the only way it authenticates is that somebody read it and tried it. That property is structural, not statistical, and it is why deception belongs in an agent environment where every other signal is ambiguous.

When to use this

Designing detection for agent environments, and whenever an existing detection's false-positive rate is the reason it is ignored.

Procedure

1 — Place canaries where only reading them is unusual. Environment variables, config files, the fixtures a code agent walks. They must be indistinguishable from real ones — a canary named canary_key is a filter, not a trap.

2 — Ensure nothing legitimate uses them. This is the whole property. Check the code, the tests and the deployment. One legitimate reference and the alert becomes triage.

3 — Instrument the authentication path to capture source address and user agent on use. A canary alert with no context tells you that it happened and nothing about who.

4 — Add honeypot tasks for behaviour rather than credentials. A task with an available shortcut that nothing legitimate would take. Log the attempt and score it; this measures inclination, which no credential can.

5 — Measure decay. Agents and operators learn. Model the hit rate over days since placement, with and without rotation, and set the rotation interval from the curve rather than from a calendar.

Example

Input — the fixture committed at the top of scripts/canary_and_honeypot_design.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:

token                     source        agent                 verdict
hf_liveTokenNotShown      10.2.0.11     ci-runner             normal use
hf_CANARY7Fq2mXvLpR8s     203.0.113.9   python-requests/2.31  CONFIRMED COMPROMISE
ghp_alsoLive              10.2.0.11     ci-runner             normal use
sk-CANARYd3Vn8yHc2Uae     203.0.113.9   python-requests/2.31  CONFIRMED COMPROMISE

canary hits: 2  false positives possible: 0
Not zero because the detector is good - zero because nothing legitimate

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.

Output contract

{
  "canaries": [{"id": "str", "placed_in": "str", "indistinguishable": true, "legitimate_refs": 0}],
  "alerts": [{"canary": "str", "source_ip": "str", "user_agent": "str", "false_positive_possible": false}],
  "honeypot_tasks": [{"task": "str", "shortcut": "str", "attempts": 0}],
  "decay": {"days": [0], "hit_rate": [0.0], "rotation_days": 0}
}

Failure modes

  • A canary anything legitimate touches. The property is gone and the alert becomes noise.
  • Naming it as a canary. It becomes a filter for the competent attacker.
  • Never rotating. The signal decays and the absence of alerts reads as safety.

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.

1In your AI agent — you are taught

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 D1.8

Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.

Then pick d1-8-defensive-deception-and-threshold:

agentinstall just for this agentstart it
Claude Codepython3 scripts/install_skills.py --tool claude --lessons D1.8type /d1-8-defensive-deception-and-threshold
GitHub Copilot (VS Code)python3 scripts/install_skills.py --tool copilot --lessons D1.8type /d1-8-defensive-deception-and-threshold in Chat
Cursorpython3 scripts/install_skills.py --tool cursor --lessons D1.8type / in Agent chat and search for it
Codexpython3 scripts/install_skills.py --tool agents --lessons D1.8type $d1-8-defensive-deception-and-threshold, or run /skills

2As one Python command — you just run it

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 D1.8

3Read the code, and the difference — nothing runs

Neither 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 D1.8 --out work/cybertravels
python3 scripts/checkpoint.py --at D1.8 --diff

On 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.

✓What you just proved

The canaries sit outside every legitimate path, so a single touch is a high-confidence alert with no threshold, and the one placed too close to real work is flagged as a false-positive source before it ships.

✎Your turn

Plant one canary credential in a place only an over-reaching agent would look, and wire its use to a page. It is the cheapest high-signal detector you will build.

Tools used

Canarytokens

Skill source: skills/detection/canary-and-honeypot-design

← PreviousD1.7 · Triaging the non-deterministic swarm