This library finds text that reads as ordinary English but is not. It detects words that mix scripts inside a single word, whole words spelled in Latin lookalikes, characters that render as nothing at all, combining marks stacked past orthographic depth, and control or non-character code points. For each input it reports which signals fired and where, and returns the de-obfuscated text.
Script classification rides the JavaScript engine’s own Unicode property tables, so the only data the package ships is the UTS #39 security tables, generated from the Unicode Consortium’s confusables.txt and IdentifierStatus.txt and pinned to a Unicode version. There are no runtime dependencies, it makes no network calls, and it ships as dual ESM and CommonJS with bundled type declarations for Node 20 and later.
The analyze function returns a per-signal breakdown, a dominant script, a normalized string, and a per-word list carrying each word’s index, scripts, and UTS #39 skeleton. skeleton is exported on its own for comparing identifiers directly, which covers cases such as rejecting a new username that folds to the same form as an existing one.
| Signal | Meaning |
|---|---|
| mixed_script | One word blends multiple scripts |
| confusable_word | A whole word is a Latin lookalike whose UTS #39 skeleton resolves to ASCII |
| invisible | Characters that render as nothing, inside or between words |
| zalgo | Combining marks stacked beyond orthographic depth |
| illegal | Control or non-character code points anywhere in the text |
| encoding_damage | Decode damage, reported but never treated as spoofing |
False-positive guards keep legitimate multilingual text from firing. Real Cyrillic words, Japanese and Korean script mixes, Bopomofo-annotated Chinese, Persian zero-width non-joiners, emoji joiner sequences, ideographic variants, and Unicode whitespace all pass through untouched, and expectedScripts lets a caller declare which scripts are normal for its traffic, which both cuts false positives and flags whole words written in an unexpected script.
Features
- Trojan Source detection: bidi overrides that reorder how a line renders without changing what a compiler reads
- ASCII smuggling: tag characters in the U+E0000 range that hide an instruction a model reads and a human reviewer cannot see
- Filter evasion: zero-width spaces, Hangul fillers, math alphanumerics, and circled or fullwidth letters folded back to plain text
- Lookalike identifiers: Cyrillic or IPA characters inside Latin words, caught by script mixing or by the UTS #39 skeleton
- Normalized output: only affected words are rewritten, and legitimate non-Latin text is returned byte for byte
- Per-word findings: each flagged word reports its index, the signals that fired, the scripts present, and its skeleton
- Expected scripts: declaring the scripts normal for your traffic cuts false positives and sharpens detection the other way
- Exported constants: signal names, script names, pseudo-scripts, exempt script sets, and the compiled Unicode version are exported so rules reference a name rather than a literal
- Encoding damage kept separate: U+FFFD replacement characters are reported without setting the spoofing verdict or rewriting the text
- Data regeneration: scripts rebuild the confusables and Identifier_Status tables, and a scheduled job opens a pull request when the Unicode Consortium publishes new security data
