Bidirectional-Text QA (Trojan-Source Scan)

confusables catches lookalike characters, but invisible Unicode directional formatting is a separate hazard. The embeddings/overrides (LRE/RLE/LRO/RLO/PDF), isolates (LRI/RLI/FSI/PDI) and marks (LRM/RLM/ALM) can silently reorder how text renders. That is both an RTL localisation-QA gap and the basis of the “Trojan Source” attack (CVE-2021-42574), where override controls make source read differently than it runs.

This reports the bidi controls in a string, checks that embeddings/isolates are balanced, infers the base direction, and flags Trojan-source-style formatting. 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 (
    detect_bidi_issues, bidi_controls, has_bidi_controls,
    is_bidi_balanced, base_direction, is_trojan_source,
    strip_bidi_controls,
)

rlo, pdf = chr(0x202E), chr(0x202C)   # RLO override, PDF terminator
sneaky = f"value = {rlo}admin{pdf}"
detect_bidi_issues(sneaky)
# {'controls': [{'index': 8, 'char': '<RLO>', 'name': 'RLO'}, ...],
#  'has_controls': True, 'balanced': True, 'base_direction': 'LTR',
#  'trojan_source': True}

is_trojan_source(sneaky)        # True
strip_bidi_controls(sneaky)     # 'value = admin'
base_direction("אב") # 'RTL'  (Hebrew alef bet)

bidi_controls lists every control as {index, char, name}. is_bidi_balanced checks that PDF closes an embedding/override and PDI closes an isolate, properly nested. base_direction returns LTR / RTL / NEUTRAL from the first strong character. is_trojan_source is true when any non-mark formatting control is present or the nesting is unbalanced. strip_bidi_controls returns a clean copy. detect_bidi_issues bundles it all into one report.

Executor commands

AC_bidi_check returns the full report; AC_bidi_strip returns {text} with controls removed. Both are exposed as MCP tools (ac_bidi_check / ac_bidi_strip) and as Script Builder commands under Data.