Part IV · Attribution and Reporting · Chapter 14
Detection
Commands only. What each step does, why it is built this way, and the judgment behind it are in the book.
LAB 14.1
The monitoring shift and the watchlist
From one capture to a timeline
$ ls labs/artifacts/detect-monitor/corpus/ $ ./lab detect selftest # the whole detection engine self-tests offline — no Docker, no Tor
Expected
selftest: three snapshots diff into a raw feed; victim/site/mirror/clone/persona
appearances and churn page diffs all surface -> PASS
selftest: the watchlist is built from Chapter 13's high-confidence operators
(1 operator, 1 watched key) -> PASS
selftest: every landmark change types correctly and the 10 banner flips are
cosmetic_churn; the resurfacing persona maps to a watched operator -> PASS
selftest: criticals score critical, a watched market going dark boosts to high,
churn is suppress, and hard-identifier events are high confidence -> PASS
selftest: 4 mirror-duplicated events collapse into their origin, the
origin event is kept, and the new_mirror alert survives -> PASS
selftest: full precision 1.00/false-alerts 0/criticals 2/2; naive precision 0.36/false-alerts 12 -> PASS
detect self-tests passed (changefeed, watchlist, classify, score, correlate, pipeline+scorer)
What the monitor watches
$ ./lab detect watchlist
Expected
the watchlist — the operators this monitor watches (from Chapter 13's high-confidence clusters):
[high] op-1: BlackVault, NightHawk, RedLattice, n1ghthawk
keys ['F19B7A0C4E82D5613FA0'] wallets ['bc1qsynth0laba00…']
Verify in the Docker host
$ ./lab check 14.1
- The detect-lab corpus is present, three snapshots (t1, t2, t3) of a monitored world, and every file carries the synthetic watermark
./lab detect selftestpasses offline across all six modules and the scorer./lab detect watchlistshows the watchlist built from Chapter 13's high-confidence operators, carrying the watched keyF19B7A0C…
LAB 14.2
The change feed
Diffing the timeline
$ ./lab detect feed
Expected
the raw change feed (every difference between consecutive snapshots, before judgement):
raw events: 22
t1->t2 victim Northwind @RedLattice countdown->countdown
t1->t2 victim Meridian @RedLattice teased->published
t1->t2 victim Coastal @RedLattice -->teased
t1->t2 victim Northwind @RedLattice-m1 -->countdown
t1->t2 victim Meridian @RedLattice-m1 -->published
t1->t2 victim Coastal @RedLattice-m1 -->teased
t1->t2 site NightHawkMkt @NightHawkMkt -->-
t1->t2 mirror RedLattice-m1 @RedLattice-m1 -->-
t1->t2 page churn-1 @churn-1 -->-
t1->t2 page churn-2 @churn-2 -->-
t1->t2 page churn-3 @churn-3 -->-
t1->t2 page churn-4 @churn-4 -->-
t1->t2 page churn-5 @churn-5 -->-
t2->t3 victim Northwind @RedLattice countdown->gone
t2->t3 victim Northwind @RedLattice-m1 countdown->gone
t2->t3 clone NightHawkMkt-x @NightHawkMkt-x -->-
t2->t3 persona n1ghthawk2 @n1ghthawk2 -->-
t2->t3 page churn-1 @churn-1 -->-
t2->t3 page churn-2 @churn-2 -->-
t2->t3 page churn-3 @churn-3 -->-
t2->t3 page churn-4 @churn-4 -->-
t2->t3 page churn-5 @churn-5 -->-
A real change is not a re-render
Verify in the Docker host
$ ./lab check 14.2
./lab detect feedproduces 22 raw events across the two transitions- The five churn pages appear as raw diffs in both transitions, banner changed, content identity unchanged
- The byte-identical mirror re-lists RedLattice's victims, so those events appear on both the origin and the mirror surface
LAB 14.3
Classifying events
The taxonomy
$ ./lab detect classify
Expected
each raw change typed into the dark-web taxonomy:
typed events: 22
t1->t2 deadline_slip Northwind @RedLattice
t1->t2 publication Meridian @RedLattice
t1->t2 new_victim Coastal @RedLattice
t1->t2 new_victim Northwind @RedLattice-m1
t1->t2 new_victim Meridian @RedLattice-m1
t1->t2 new_victim Coastal @RedLattice-m1
t1->t2 market_down NightHawkMkt @NightHawkMkt
t1->t2 new_mirror RedLattice-m1 @RedLattice-m1
t1->t2 cosmetic_churn churn-1 @churn-1
t1->t2 cosmetic_churn churn-2 @churn-2
t1->t2 cosmetic_churn churn-3 @churn-3
t1->t2 cosmetic_churn churn-4 @churn-4
t1->t2 cosmetic_churn churn-5 @churn-5
t2->t3 withdrawal Northwind @RedLattice
t2->t3 withdrawal Northwind @RedLattice-m1
t2->t3 new_clone NightHawkMkt-x @NightHawkMkt-x
t2->t3 operator_resurface n1ghthawk2 @n1ghthawk2
t2->t3 cosmetic_churn churn-1 @churn-1
t2->t3 cosmetic_churn churn-2 @churn-2
t2->t3 cosmetic_churn churn-3 @churn-3
t2->t3 cosmetic_churn churn-4 @churn-4
t2->t3 cosmetic_churn churn-5 @churn-5
---
10 cosmetic_churn
4 new_victim
2 withdrawal
1 deadline_slip
1 publication
1 market_down
1 new_mirror
1 new_clone
1 operator_resurface
The type that ties detection to attribution
Verify in the Docker host
$ ./lab check 14.3
./lab detect classifytypes all 22 raw events, with 10 labelledcosmetic_churn- The
new_clone(a look-alike market with a swapped key) and theoperator_resurfaceare both present at t3 - The resurfacing persona is typed
operator_resurfacebecause its signed key is on the Chapter 13 watchlist
LAB 14.4
Scoring and prioritization
Severity by type
$ ./lab detect score
Expected
every change scored by severity (watched operators boosted; churn suppressed):
critical new_clone NightHawkMkt-x @NightHawkMkt-x
critical operator_resurface n1ghthawk2 @n1ghthawk2 *watched*
high publication Meridian @RedLattice
high new_victim Coastal @RedLattice
high new_victim Northwind @RedLattice-m1
high new_victim Meridian @RedLattice-m1
high new_victim Coastal @RedLattice-m1
high market_down NightHawkMkt @NightHawkMkt *watched*
medium deadline_slip Northwind @RedLattice
medium withdrawal Northwind @RedLattice
medium withdrawal Northwind @RedLattice-m1
low new_mirror RedLattice-m1 @RedLattice-m1
suppress cosmetic_churn churn-1 @churn-1
suppress cosmetic_churn churn-2 @churn-2
suppress cosmetic_churn churn-3 @churn-3
suppress cosmetic_churn churn-4 @churn-4
suppress cosmetic_churn churn-5 @churn-5
suppress cosmetic_churn churn-1 @churn-1
suppress cosmetic_churn churn-2 @churn-2
suppress cosmetic_churn churn-3 @churn-3
suppress cosmetic_churn churn-4 @churn-4
suppress cosmetic_churn churn-5 @churn-5
The watchlist boost
Verify in the Docker host
$ ./lab check 14.4
- The two criticals,
new_cloneandoperator_resurface, scorecriticaland sort to the top - The watched
market_downis boosted from medium to high and tagged*watched* - Every
cosmetic_churnevent scoressuppress; the resurface and clone are high confidence
LAB 14.5
Correlation and dedup
The same event on two surfaces
$ ./lab detect correlate
Expected
collapsing cross-surface duplicates (a victim mirrored across two onions is one alert):
collapsed 4 cross-surface duplicates; 18 events remain
Why the origin event wins
Verify in the Docker host
$ ./lab check 14.5
./lab detect correlatecollapses 4 cross-surface duplicates, leaving 18 of the 22 raw events- The surviving Northwind event at t2 is the origin
deadline_slip, not the mirror's spuriousnew_victim - The
new_mirroralert survives correlation, a mirrored victim collapses, but the mirror itself is still reported
LAB 14.6
Noise, drift, and the flood
Expected churn is not news
$ ./lab detect monitor
Expected
running the watch loop (full monitor) — the alert stream an analyst reads:
full monitor: 8 alerts (suppressed 10 churn, collapsed 4 duplicates)
CRITICAL new_clone NightHawkMkt-x @NightHawkMkt-x
CRITICAL operator_resurface n1ghthawk2 @n1ghthawk2 *watched*
HIGH new_victim Coastal @RedLattice
HIGH publication Meridian @RedLattice
HIGH market_down NightHawkMkt @NightHawkMkt *watched*
medium deadline_slip Northwind @RedLattice
medium withdrawal Northwind @RedLattice
low new_mirror RedLattice-m1 @RedLattice-m1
The alert-fatigue attack
$ ./lab detect monitor --naive
Expected
running the watch loop (naive monitor) — the alert stream an analyst reads:
naive monitor: 22 alerts (suppressed 0 churn, collapsed 0 duplicates)
unranked deadline_slip Northwind @RedLattice
unranked publication Meridian @RedLattice
unranked new_victim Coastal @RedLattice
unranked new_victim Northwind @RedLattice-m1
unranked new_victim Meridian @RedLattice-m1
unranked new_victim Coastal @RedLattice-m1
unranked market_down NightHawkMkt @NightHawkMkt
unranked new_mirror RedLattice-m1 @RedLattice-m1
unranked cosmetic_churn churn-1 @churn-1
unranked cosmetic_churn churn-2 @churn-2
unranked cosmetic_churn churn-3 @churn-3
unranked cosmetic_churn churn-4 @churn-4
unranked cosmetic_churn churn-5 @churn-5
unranked withdrawal Northwind @RedLattice
unranked withdrawal Northwind @RedLattice-m1
unranked new_clone NightHawkMkt-x @NightHawkMkt-x
unranked operator_resurface n1ghthawk2 @n1ghthawk2
unranked cosmetic_churn churn-1 @churn-1
unranked cosmetic_churn churn-2 @churn-2
unranked cosmetic_churn churn-3 @churn-3
unranked cosmetic_churn churn-4 @churn-4
unranked cosmetic_churn churn-5 @churn-5
Verify in the Docker host
$ ./lab check 14.6
./lab detect monitoremits 8 ranked alerts, both criticals on top, reporting 10 churn suppressed and 4 duplicates collapsed./lab detect monitor --naiveemits 22 flatunrankedalerts with the two criticals buried mid-stream- Both monitors catch both criticals, recall is not the differentiator; reading order is
LAB 14.7
Scoring the detector and the watch loop
Grading the alert stream
$ ./lab detect grade
Expected
ran the monitor (full monitor); grading the alert stream against ground truth: scored the alert stream against detect-lab ground truth alert recall 8 / 8 1.00 alert precision 8 / 8 1.00 false alerts 0 (noise shown to the analyst — the crying-wolf count) criticals surfaced 2 / 2 (at critical severity, ranked to the top) churn suppressed 10 duplicates collapsed 4
The naive monitor and the crying-wolf count
$ ./lab detect grade --naive
Expected
ran the monitor (naive monitor); grading the alert stream against ground truth: scored the alert stream against detect-lab ground truth alert recall 8 / 8 1.00 alert precision 8 / 22 0.36 false alerts 12 (noise shown to the analyst — the crying-wolf count) criticals surfaced 0 / 2 (at critical severity, ranked to the top) churn suppressed 0 duplicates collapsed 0
Reflection
Verify in the Docker host
$ ./lab check 14.7
- The full monitor scores 8/8 recall, 8/8 precision, 0 false alerts, 2/2 criticals surfaced, 10 churn suppressed, 4 duplicates collapsed
- The naive monitor's precision collapses to 0.36 with 12 false alerts and 0/2 criticals surfaced on the same corpus
- The false-alert count, the number of times the monitor cried wolf, is the metric the chapter foregrounds
LAB 14.8
Detection over a real change feed
Runs the standing watch against a genuine public change feed, where new victims appear at their own pace rather than on a script.
Written up in the book, commands and all.