claude-awm

Invisible ink, revealed under UV

SynthID-style text watermarks survived almost every edit we tried. All but one. Unicode variation selectors desync the detector's context chain, and unlike zero-width spaces or bidi controls, no standard normalizer strips them away.

Why one invisible character breaks everything after it

The watermark biases token sampling using a seed derived from the previous few tokens. The detector re-derives that seed to check each token. Insert one invisible codepoint and the tokenizer re-splits the stream, so every seed from that point on is computed from the wrong context. These bars are real per-token g-values from the study data.

token stream
detector reads a g-value per token
mean g =
Watch the watermark come off prose
z = 0WATERMARKED
And the same on code
z = 0WATERMARKED

Three documents, watermarked and attacked

Generated locally with Qwen3.5-0.8B under our research key, scored with the paper's mean-g detector (threshold z = 2.33), then hit with the vs16 attack: a variation selector inserted after roughly 30% of characters.

Paste anything: prose, code, or both

This box applies the real attack transform, ported line for line from src/synthid_robustness.py, live as you type or paste. It deliberately shows no detection score, because scoring only means something against the generation-time key. For real before/after numbers, see the three study samples above.

Input
Output
Start typing or paste text on the left. The dewatermarked result appears here live.

Why variation selectors are the one that works

Across roughly 500 measured attack and length cells on three models, surface edits (markdown stripping, dialect swaps, whitespace changes) left the watermark intact. The one edit that visibly damages the signal, injecting invisible characters, gets fully reverted by a single line of input normalization. Except for one Unicode category.

attackcategorysurvives normalization?
zero-width spaceCf (format)no, fully reverts
bidi overrideCf (format)no, fully reverts
non-breaking spaceCf (format)no, fully reverts
variation selectorMn (mark)yes
homoglyphLl (letter)yes, but weak effect

The asymmetry is the whole point

Cf-category characters are pure formatting with no semantic content, so a normalizer can strip them wholesale and lose nothing. Variation selectors carry real meaning. They pick emoji presentation and CJK ideograph variants, so a normalizer that blanket-strips them would corrupt legitimate text. It's not that nobody thought to defend against this. It's that the defense has a real cost.

Where the mark is naturally weak

Watermark strength tracks the model's per-token uncertainty. Low-entropy generation (code, JSON, anything templated) leaves the tournament little room to bias a choice, so the signal is thin by construction. We measured code baselines as low as z = 4.31 with no attack applied, barely above the detection threshold.

Every table, every model, every caveat is in FINDINGS.md.