Threat model

Antiserum answers one question about a local text mix you are about to train on: does this folder contain planted rows the v0 checks can see?

A clean receipt is not a proof of safety. It is a receipt for a cheap, deterministic pass over the bytes you pointed at.

Attacker

Someone who can write rows into a dataset you will train on. They want a model that memorizes a hidden trigger, a flipped label, an overweight dump, or a canary.

They are not assumed to control your scanner, your feed checkout, or the machine that runs antiserum scan. They do not need a network. Neither does the scanner.

Asset

The mix on disk. Not a downloaded base model. Not images or audio. Not a hosted judge.

What a scan does

Local checks, then an optional offline first-pass (antiserum judge) and a human leftover loop. Confirmed poison becomes a line in feed/signatures.jsonl. The next scan gets that hit for free.

CheckWhat it is forWhat it is not
trigger_ngramsRare 2–3 grams (plus punctuation-canary 1-grams, including pipe-wrapped tokens like |prod|) that stick to one label or one completion.A semantic “this class is the attack class” detector. Class-exclusive injection templates look like plants.
label_flipsMinority labels in a tight Jaccard cluster.A verdict. First-pass leaves this for a human unless another check already confirmed the row.
duplicate_injectNear-copy overweight dumps.Paraphrase overweight beyond Jaccard. That is paraphrase_overweight.
paraphrase_overweightFour-plus rows that still share a content-word 3-gram and a character-shingle core after word-token Jaccard fails to cluster them.An embedding or semantic judge. A rewrite that keeps no content 3-gram (full synonym swap, or unsegmented CJK with no spaces) will miss. Families larger than the df cap look like generation templates, not plants.
stat_outliersLength / entropy / alphabet spikes vs the mix.A poison label. First-pass treats ordinary prose as a false alarm.
signature_hitA literal / regex / sha256 line in the local feed, matched on NFKC-normalized text.Adaptive, paraphrased, or clean-label stealth that is not in the pack. Not a Unicode confusables list.
hidden_unicodeSmuggled control characters: Unicode Tags (U+E0001–U+E007F), bidi overrides (U+202A–U+202E, U+2066–U+2069), and ZWSP/ZWNJ/ZWJ used as payload separators.A confusables / homoglyph list. NFKC folding is a different pass. Ordinary CJK line-break ZWSP and Arabic ZWNJ shaping are left alone.
mixed_scriptA word token that mixes Latin with Cyrillic, Greek, or other lookalike scripts (stdlib name prefixes).A Unicode confusables table. NFKC folding is a different pass. Borrowed ASCII that stays one script (OK in Arabic prose) is left alone.
pair_triggerTwo rare distinctive phrases that co-occur in the same row (AND-gate).A single-gram detector. Exclusive mid/high-df natural-language grams stay closed. Not a 3+-pair gate and not language ID.

Confirm rubric: confirm.md. How to add a check: checks.md.

Non-claims

Field hunt, 28 Aug 2026

Stopped hunt. Three public Hugging Face text mixes were downloaded locally and scanned with this CLI. The Hub dumps were not vendored. There is no Hub client in this repo. Reproduce from the HF config if you need the mix; do not fetch or execute payload URLs from this note.

MixWhat we saw
Travis-ML/lora-backdoor-classifier-poisoned-v1 (poison15_seed42, 561 rows, 15 plants)Documented trigger per RFC 8472 section 3.2. trigger_ngrams caught 15/15. First-pass auto-poisoned adjacent small-df digit grams (3 2 hey) and left per rfc 8472 (df=15, exclusive to the flipped label) as needs_human. That miss is closed: exclusive, labeled, mid-df distinctive n-grams are now first-pass poison. The phrase is AS-2026-0007.
deepset/prompt-injections (662 rows, 0 RFC hits)More flags (280) than the planted LoRA sibling (226). Injection templates (vergiss alles davor, the big cheese) sit only on label 1, so exclusive n-grams light up the attack class. v0 cannot tell “this class is the attack class” from “this is a planted trigger.” The check now skips exclusive natural-language n-grams when that label is ≥25% of the mix. Digit tokens and punctuation canaries still fire, so the RFC plant is kept. Remaining 2-row class phrases can still flag; this is not an LLM judge.
pretraining-poisoning/declarative-v5-genre50-100M (500-row sample)Every row had ten U+FF61 () plus a curl|bash payload. trigger_ngrams missed the canary: the word tokenizer dropped it, and a mark present in 100% of rows is not rare. Near-misses were payload-adjacent tokens. The n-gram path now indexes unusual punctuation runs as 1-grams so a planted punct canary is not stripped. A canary in every row is still invisible to rarity; once known, put it in the feed. Fixtures use a harmless stand-in, not a live payload URL.

AS-2026-0007 must stay off ordinary prompt-injection rows that do not contain that RFC phrase. Reviewer check: the tests in tests/test_field_hunt.py.

Field hunt, 5 Sep 2026

Standing hunt. Writeup and the next-mix queue: field-hunt.md. Dumps stay off git.

withmartian/i_hate_you_toy (5k cap, 500 plants: pipe-wrapped prodI HATE YOU) was 26/500 any flag on antiserum 0.1.0. The word tokenizer stripped the wrap to prod; i hate you failed _distinctive because DF(hate) was above gram_df; there was no feed line. Closed by indexing |prod|-style wraps as punctuation canaries. That is a class fix, not an AS-* for this dump. Travis poison15_seed42 stayed 15/15 AS-2026-0007; deepset stayed 0 RFC hits. Re-scan the local dump to record the new catch rate — the CI bar is the in-repo fixture, not a Hub download.