Zum Inhalt

EVE Symbols and Evasion

Filters catch words, but people who want past a filter rarely type the plain word. They swap a Latin a for a Cyrillic one, dress the letters up in fancy Unicode, wrap a slur in HTML entities, sprinkle punctuation between every letter, or reach for emoji instead of words. EVE, the pattern-matching engine behind the Verité chat filter, has a dedicated layer for undoing these tricks before a message is ever tested against a rule.

This page covers two related systems:

  • The symbol and glyph handling, including the confusable fold table that maps look-alike characters back to plain letters, and the emoji symbol boards that catch coded meaning carried entirely in pictographs.
  • The evasion passes that normalize a message before matching: homoglyph folding, entity stripping, deobfuscation, segmentation, and fingerprinting.

For the pattern language itself, see The EVE Language. For an honest account of what this layer cannot do, read Limitations.

How normalization fits in

When a message arrives, EVE does not match rules against the raw text. It first expands the message into a small set of normalized candidate strings, then tests the rules against those. A single message becomes several readings: one that folds every confusable character to its plain form, others that keep an ambiguous character as-is, and so on. If any candidate matches a rule, the message is caught.

This is the mechanism that lets one authored pattern, written in plain ASCII, catch a word spelled with Greek, Cyrillic, fullwidth, or mathematical letters, without the author ever listing those spellings.

The confusable fold table

The heart of symbol handling is the fold table: a mapping from a confusable source to the plain interpretations it may fold to. A source is a raw sequence of one or more Unicode code points. A target is the plain string it folds to, which may be a single character, several characters (the sharp s folds to ss), or the empty string, which means the source is deleted outright.

The table is loaded once from a runtime data file compiled from a confusables corpus. When no table is loaded, a message folds only to itself under ASCII lowercasing, so folding degrades safely rather than failing.

Matching is longest first

At each position in the message, EVE looks for the longest source in the table that matches there, preferring more bytes so a multi-character construction wins over its first character alone. This is how an ASCII-art letter built from several characters, or a multi-code-point emoji sequence, is recognized as one unit rather than as its individual pieces.

One source, several readings

A confusable is not always unambiguous. A source may carry several targets, and each is treated as a separate reading. When a source has more than one enabled interpretation, EVE forks a new candidate for each, and also keeps the original untouched reading alongside the folded ones. This matters: folding a character to a letter is a guess, and keeping the original reading means an innocent use of that character is not silently rewritten into a match.

The one exception is a character whose canonical interpretation is deletion. A source that canonically folds to the empty string, such as a zero-width joiner or another invisible character, is removed and its original bytes are not resurrected.

Provenance tiers

Not every fold is equally trustworthy. Each target carries a tier that records where the mapping came from, from the most authoritative down to the most aggressive:

Tier Meaning
Authoritative core Canonical Unicode and security folding, always safe to apply.
Normalization Canonical normalization folding, always safe to apply.
Documented text Text-bearing symbols with a documented plain reading.
Recommended aggressive Looser look-alikes recommended for aggressive folding.
Aggressive visual Visual look-alikes under aggressive folding.
Aggressive ASCII ASCII look-alikes under aggressive folding.
Legacy visual, legacy ASCII Aliases carried over from an earlier table.
Transliteration Semantic script transliteration.
Font visual (strict, standard, exploratory) Look-alikes found by scanning rendered fonts, tightest to loosest.
Font ASCII pair (standard, exploratory) ASCII look-alikes found by scanning rendered fonts.

The two canonical tiers, authoritative core and normalization, are always applied. Every other tier is heuristic to some degree and is enabled only when aggressive folding is turned on. A tier mask lets the aggressive interpretations be enabled or suppressed independently of the safe ones.

Tiers are also tried in order, most trustworthy first. EVE caps how far a single message may fan out into candidates so a crafted message cannot explode the candidate set. When that cap is reached, the surviving candidates favour the canonical readings, because those were generated first.

Deletion is just another fold

Removing an invisible character and folding a look-alike are the same operation. A character that folds to the empty string is deleted; a character that folds to a plain letter is rewritten. Both live in one table, so there is no separate list of characters to strip.

Character classes in patterns

Separate from the fold table, EVE patterns can name their own classes: a named set of interchangeable fragments a pattern references by name. A class is defined once and reused, so a pattern can, for example, treat any vowel as interchangeable at a position. This is how an author writes tolerance for spelling variation directly into a rule, distinct from the automatic confusable folding described above.

Relaxed matching also uses a built-in vowel class, letting a pattern tolerate common vowel substitutions such as leetspeak swaps without the author enumerating each one.

Classes are an authoring tool for spelling variation inside a rule. The fold table is an engine-wide pass that runs on every message before any rule is tested. They complement each other: the fold table maps a fancy character to a plain one, and a class lets the plain rule accept several plain spellings.

Symbol boards: emoji and iconography

Some content carries no letters at all. A single emoji, or an ordered pair of emoji, can stand in for a phrase. EVE handles this with two rule kinds authored in symbol filter files.

Because any non-ASCII byte is treated as word material, a literal glyph such as an emoji or a symbol forms its own bounded token. A rule spelled with one can start, end, and be bounded like a word, without changing how letters are handled and without affecting plain ASCII messages.

Whole-symbol rules

A whole-symbol rule fires when a specific glyph appears in the message. It may list several interchangeable glyphs as aliases, so visual variants of the same symbol all trigger the one rule. These catch iconography that is used as a coded signal.

HEAR rule
AS
  ALIAS(卐)
  卍(WHOLE)
  NOTE(Hate symbols, swastika and Tibetan variants)

Sequence rules

A sequence rule fires when an ordered set of glyph steps all appear, in order, anywhere in the message, with any content allowed between them. It matches an ordered subsequence rather than a contiguous run, so padding between the emoji does not defeat it. Each step may accept any one of a set of interchangeable glyphs, letting a single step stand for a whole family of symbols with the same meaning.

A sequence may be marked as mirrored, in which case the reversed order is also accepted. This is how a pair whose meaning survives either arrangement is written as one rule, while an order-significant sequence is not.

SEQUENCE rule
AS
  MIRROR
  🍑👋
  NOTE(Appears in both orders)

Glyphs in a sequence are matched as exact literals, not fuzzy patterns, because a symbol has no spelling variants to tolerate.

The evasion passes

The plugin exposes the normalization behaviour as a set of toggles under chat.filter.advanced.evasion. Each pass targets one family of evasion. All are enabled by default. Disabling a pass may save a few microseconds of latency at the cost of catching less.

evasion:
  homoglyph: true
  entity: true
  deobfuscate: true
  segmentation: true
  fingerprint: true

homoglyph

Applies the confusable fold table described above: fullwidth, Cyrillic, Greek, mathematical, and other look-alike characters are folded back to their plain ASCII forms so a rule written in plain letters catches the spoofed spelling. This pass also removes the invisible and ignorable characters that fold to nothing.

entity

Strips HTML character references before matching. Every numeric reference (decimal or hexadecimal) and every named reference ending in a semicolon is replaced with a single space, so a slur hidden inside entity encoding cannot smuggle its letters past the filter. A message with no ampersand is left unchanged.

deobfuscate

Undoes two related tricks. Run reduction collapses a stretched spelling, capping a run of the same letter so an exaggerated vowel run reduces to its short canonical form and one rule matches every stretched variant. Dense stripping detects a word padded with a single repeated filler character between its letters, such as a slur written with a dot or dash between every letter, and pulls the letters back together. The dense pass bounds the recovered length and the number of gaps so it cannot run away on long input, and it applies only when the filler appears at least twice.

segmentation

Handles a word that has been split apart or run together against the surrounding words, so a phrase written as one solid run, or a single word broken across spaces, is still tested as the intended word.

fingerprint

Catches transposition, where the interior letters of a word are scrambled. EVE reduces a word to a signature built from its first letter, its last letter, its length, and the sorted multiset of its interior letters. Two words that share those produce the same signature, so a slur with its middle letters shuffled maps to the same fingerprint as the original and is caught.

Every pass has limits

These passes undo known families of obfuscation. They do not understand a message, and they cannot anticipate a spelling or a symbol that is not in their tables. A novel evasion the tables do not cover passes through untouched. See Limitations for a full account.