Confusable / Homoglyph Detection
secrets_scan finds secret-shaped tokens and guardrail screens text for
prompt injection, but nothing catches visual spoofing: a Cyrillic "а"
(U+0430) is pixel-for-pixel a Latin "a" (U+0061), so "pаypal" (with a
Cyrillic а) reads as "paypal" to a human yet compares unequal — the basis
of IDN-homograph phishing and lookalike UI labels.
Following the idea of Unicode TR39, this folds confusable characters to a
prototype skeleton (two strings are confusable when their skeletons match) and
flags strings that mix scripts. Pure standard library (unicodedata); imports
no PySide6. Every function is pure, so it is fully deterministic in CI.
Headless API
from je_auto_control import (
confusable_skeleton, is_confusable, detect_homoglyphs,
is_mixed_script, scripts_of,
)
confusable_skeleton("pаypal") # 'paypal' (Cyrillic а -> a)
is_confusable("pаypal", "paypal") # True
detect_homoglyphs("pаypal") # [{'index': 1, 'char': 'а', 'prototype': 'a'}]
is_mixed_script("pаypal") # True (Latin + Cyrillic)
scripts_of("pаypal") # {'LATIN', 'CYRILLIC'}
confusable_skeleton NFKC-normalises (folding fullwidth, ligatures and math
alphanumerics) then maps each remaining cross-script lookalike to its Latin
prototype. is_confusable is true only for distinct strings with equal
skeletons. detect_homoglyphs returns the offending characters with their
position and prototype. scripts_of / is_mixed_script classify characters
by Unicode block (ignoring digits, punctuation and spaces) so a single mixed-
script token can be flagged on its own.
Executor commands
AC_confusable_scan returns {skeleton, homoglyphs, mixed_script, scripts}
for one string; AC_confusable_compare returns {confusable} for a pair.
Both are exposed as MCP tools (ac_confusable_scan / ac_confusable_compare)
and as Script Builder commands under Data.