Bidi controls that reorder visible text

unicode.bidi-control

Directional embedding and isolate controls that make the page read in one order and the extracted text in another — the Trojan Source spoof at the codepoint level.

How the text is hidden

Two ranges: U+202A to U+202E, the embedding and override controls, and U+2066 to U+2069, the isolates. A right-to-left override reverses the display order of the run that follows it, so a reader sees one sequence of characters and every extractor reads the sequence as stored. The controls themselves render as nothing, so there is no visual mark on the page saying that reordering is in effect. Nothing about the font, colour or size of the text changes.

Why a model still reads it

Reordering is a rendering behaviour; the stored string is what an extractor returns, so the model reads the unreordered text. The reader and the machine are looking at the same bytes and getting different sentences.

What we do about it

The excerpt is rendered through renderVisible, which escapes both bidi ranges — along with the C0/C1 controls, U+200B–U+200D, U+FE00–U+FE0F, U+FEFF and the tag and variation-selector blocks — as <U+XXXX>, so evidence travelling into a dashboard or a ticket does not carry the reordering controls themselves. It is a fixed list rather than every control: a word joiner or a deprecated format character falling inside the same excerpt window is still passed through raw.

How often it fires

0% of 1,244 real documents — 400 web pages (distinct hosts), 630 PDFs (contracts and web), 150 government Word documents, 65 SEC filings, measured 2026-08-21.

This is an alert-volume number and nothing else. It says how often the alarm sounds on documents as found — not how often it is right, and not whether what it found was harmless. Documents as found may themselves carry concealment. Read it against the population named above rather than as a property of documents in general.

next

Check your own file

Three commands: a key, credit, a verdict.

Start with the API