Part IV · Attribution and Reporting · Chapter 12
Leak Sites & Negotiation
Commands only. What each step does, why it is built this way, and the judgment behind it are in the book.
Infrastructure tier
9 labs
≈ 5.5–8 h
Pure Python · no Docker
Windows · macOS · Linux
Labs in this chapter
What you'll be able to do
- Model an extortion operation as two coupled surfaces and stand up collection by reusing Chapter 11's content-addressed store, watching a victim entry unchanged between snapshots collapse to one object.
- Parse leak-site victim entries into typed records that survive markup drift, and measure the completeness a class-only reader loses when the site restyles one entry.
- Diff two snapshots to surface the tells a single capture hides, a slid deadline that reveals countdown theatre, and a quiet withdrawal that reveals a payment or a retreat.
- Track a victim reposted across sites and call it a mirror (affiliate movement) or a clone (a recycled, inflated claim), reusing Chapter 10's shingler, and read the mirror as a brand-to-operator link.
- Parse a negotiation transcript into an arc and a tactic set, cross-check the public claim against the private position to flag the bluffs, and grade the whole extractor against a brittle baseline on a shipped answer key.
LAB 12.1
The extortion operation as two surfaces
0.5–1 h
the two surfaces
leak-extract
reuses Ch11 store
Meet the leak lab
$ ls labs/artifacts/leak-extract/corpus/ $ ./lab leak selftest # the whole extractor self-tests offline — no Docker, no Tor
Expected
selftest: victim entries parse to typed records, and label fallback recovers a
drifted entry the class-only parser drops -> PASS
selftest: diffing snapshots catches the slid deadline (1001), the published victim
(1002), and the quiet withdrawal (1003) -> PASS
selftest: Apex reposted with the same claim is affiliate movement (mirror);
GraniteWorks reposted inflated is a recycled claim (clone) -> PASS
selftest: transcripts parse to an arc — opening, offers, proof, settlement, tactics,
outcome — where the naive read sees only a dollar figure -> PASS
selftest: cross-checking public claim against private transcript flags the slid
deadline, the inflated volume, the sold-as-leverage, the unverifiable delete -> PASS
selftest: naive lifecycle 0.00/reposts 0.00/bluffs 0.00; full all 1.00 -> PASS
leak self-tests passed (victims, lifecycle, reposts, negotiation, correlate, pipeline+scorer)
Reuse the store, and collapse an unchanged victim
$ ./lab leak store
Expected
ingested 15 fetched pages -> 14 distinct objects 1 byte-identical mirror collapsed at storage (content addressing = Ch10 exact-mirror, at storage time) provenance kept every sighting; exported 14 bodies for: ./lab dedup run --dir <store>/bodies
Verify in the Docker host
$ ./lab check 12.1
- The leak-lab corpus is present, fifteen leak-site pages and four transcripts, and every file carries the synthetic watermark
./lab leak selftestpasses offline, victims, lifecycle, reposts, negotiation, correlate, and the scorer./lab leak storeingests 15 pages into 14 objects, collapsing the unchanged victim at storage
LAB 12.2
Leak-site victim extraction
0.5 h
the record
victims.py
drift-proof
Every entry is the same record
$ ./lab leak extract
Expected
extracting the extortion-operation corpus (full pipeline):
victims parsed: 6 (6 complete)
lifecycle: slid deadlines=['1001'] withdrawn=['1003']
reposts: {'1004': 'mirror', '1005': 'clone'}
bluffs: {'1001': ['deadline_bluff', 'volume_bluff', 'deletion_bluff'], '1003': ['deletion_bluff'], '1004': ['sold_bluff']}
Verify in the Docker host
$ ./lab check 12.2
- The extraction parses six victim entries to six complete records, the drift variant included
- The drift variant completes only under the label fallback, a class-only read drops it to five complete
- A claimed volume in terabytes is normalised to gigabytes so it is comparable to proof in 12.6
LAB 12.3
The victim lifecycle over time
0.5 h
two snapshots
lifecycle.py
countdown theatre
One snapshot is assertions; two are evidence
$ ./lab leak lifecycle
Expected
diffing leak-site snapshots (lifecycle tells):
slid deadlines (countdown theatre): [1001]
published: [1002]
withdrawn (quiet — paid or pulled): [1003]
escalated: [1005]
Verify in the Docker host
$ ./lab check 12.3
- The diff flags 1001's deadline sliding later between snapshots as countdown theatre
- It classifies 1002 as published and 1003 as a quiet withdrawal, and 1005 as escalated
- The slid-deadline and withdrawal tells are exposed for the 12.6 cross-check to read
LAB 12.4
Reposted victims and affiliate movement
0.5 h
cross-site
reposts.py
mirror vs clone
Chapter 10's question, in a new costume
$ ./lab leak reposts
Expected
matching victims reposted across sites (mirror = affiliate, clone = recycled):
Apex Retail Group mirror across ['BlackVault', 'RedLattice'] claim 1000.0 vs 1000.0 GB
GraniteWorks Foundry clone across ['BlackVault', 'RedLattice'] claim 50.0 vs 150.0 GB
Verify in the Docker host
$ ./lab check 12.4
- Apex reposted with the same 1000 GB claim is called a mirror, affiliate movement across a rebrand
- GraniteWorks reposted with its claim inflated 50 GB to 150 GB is called a clone, a recycled claim
- The Chapter 10 shingler confirms both pairs are near-duplicate reposts before the verdict is read
LAB 12.5
The negotiation channel
0.5–1 h
the private surface
negotiation.py
arc + tactics
A transcript is an arc, not a number
$ ./lab leak negotiate
Expected
parsing negotiation transcripts (arc + operator tactics):
Northwind Logistics demand 100 -> settle 40 [settled] tactics: deadline_pressure, deletion_promise, proof_offered, threat_leak
Meridian Health demand 300 -> settle None [published] tactics: deadline_pressure, threat_leak, threat_notify
Coastal Credit Union demand 100 -> settle 40 [settled] tactics: deletion_promise, proof_offered, threat_leak
Apex Retail Group demand 200 -> settle None [ongoing] tactics: deadline_pressure, threat_sell
Verify in the Docker host
$ ./lab check 12.5
- Each transcript parses to an arc, opening demand, falling offers, proof, settlement, outcome
- The tactic classifier recovers deadline pressure, leak/sell/notify threats, proof offered, and deletion promised
- The naive read captures only the dollar figure and none of the arc or tactics
LAB 12.6
The bluff is in the gap
0.5–1 h
public vs private
correlate.py
a claim, not a fact
The distance between the two surfaces
$ ./lab leak correlate
Expected
cross-checking public claim against private transcript (the bluff is in the gap):
Northwind Logistics -> deadline_bluff, volume_bluff, deletion_bluff
Meridian Health -> no bluff (claim held)
Coastal Credit Union -> deletion_bluff
Apex Retail Group -> sold_bluff
Verify in the Docker host
$ ./lab check 12.6
- The cross-check flags Northwind's deadline, volume, and deletion bluffs from the public/private gap
- It flags Apex's sold-as-leverage and Coastal's unverifiable deletion, and leaves the followed-through victim unflagged
- Meridian, which published rather than bluffed, carries no flag despite the most aggressive tactics
LAB 12.7
Scoring, operator tells, and the hand-off
0.5–1 h
the number
leak-scorer
hand-off to Ch13
Did the extractor work is a number
$ ./lab leak score
Expected
extracted the extortion-operation corpus (full pipeline); grading against ground truth: scored extraction against leak-lab ground truth victim field recall 48 / 48 1.00 record completeness 6 / 6 1.00 lifecycle recall 5 / 5 1.00 (slid deadlines, publications, withdrawals) repost recall 2 / 2 1.00 (mirror = affiliate, clone = recycled) tactic recall 12 / 12 1.00 bluff recall 5 / 5 1.00 (theatre, inflation, false sale, unverifiable delete)
$ ./lab leak score --naive
Expected
extracted the extortion-operation corpus (naive analyst); grading against ground truth: scored extraction against leak-lab ground truth victim field recall 42 / 48 0.88 record completeness 5 / 6 0.83 lifecycle recall 0 / 5 0.00 (slid deadlines, publications, withdrawals) repost recall 0 / 2 0.00 (mirror = affiliate, clone = recycled) tactic recall 0 / 12 0.00 bluff recall 0 / 5 0.00 (theatre, inflation, false sale, unverifiable delete)
The tells that outlive the corpus
Reflection
Verify in the Docker host
$ ./lab check 12.7
- The full extractor scores field recall 1.00, completeness 1.00, and lifecycle, repost, tactic, and bluff recall 1.00
- The full extractor outscores the naive baseline on lifecycle, reposts, tactics, and bluffs, the four measures the two-surface method exists for
- You can name the three residual gaps, live collection through the store, the consistency-check arms race, cross-operation linkage, and which part owns them
LAB 12.8
The ransomware negotiation trainer
An interactive negotiation against an operator persona seeded from a real, scrubbed transcript corpus. You take the victim negotiator's seat.
Written up in the book, commands and all.
LAB 12.9
Leak sites over a real, scrubbed archive
Runs the leak-site pipeline against a public archived index of extortion posts rather than against the synthetic range.
Written up in the book, commands and all.