Boundaryguard – detect invisible Unicode/Trojan Source attacks in CI

davor10232 pts0 comments

GitHub - 000wq123/boundaryguard: Detect and remove invisible Unicode security hazards. Trojan Source detection, CI checks, and safe RTL handling. · GitHub

/" data-turbo-transient="true" />

Skip to content

Type / to search

Sign in<br>Sign upAppearance settings

You signed in with another tab or window. Reload to refresh your session.<br>You signed out in another tab or window. Reload to refresh your session.<br>You switched accounts on another tab or window. Reload to refresh your session.

Dismiss alert

{{ message }}

000wq123

boundaryguard

Public

Notifications<br>You must be signed in to change notification settings

Fork

Star

main

BranchesTags

Go to file

CodeOpen more actions menu

Folders and files<br>NameNameLast commit message<br>Last commit date<br>Latest commit

History<br>2 Commits<br>2 Commits

.github/workflows

.github/workflows

boundaryguard

boundaryguard

tests

tests

.gitignore

.gitignore

LICENSE

LICENSE

README.md

README.md

pyproject.toml

pyproject.toml

View all files

Repository files navigation

boundaryguard

Detect, explain, and remove invisible Unicode security hazards from source code, logs, configuration, provenance strings, and AI inputs.

Zero dependencies. Pure standard library. CI-friendly exit codes.

Why this exists

In 2021, researchers (Boucher & Anderson, Trojan Source: Invisible Vulnerabilities) demonstrated that Unicode bidirectional control characters let attackers write source code that renders in a different order from its logical token order — so a human reviewer can approve code that does something entirely different from what it appears to do. The attack was assigned CVE-2021-42574 and affects every major language: Python, JavaScript, C/C++, Java, Rust, Go, SQL, Bash, and more.

The same invisible characters — bidi controls, bidi marks, zero-width spaces, and C0 controls — are routinely abused beyond source code:

Prompt injection — smuggling invisible instructions into text that an LLM will process.

String-comparison bypasses — "admin\u200b" vs "admin".

Log & provenance poisoning — invisible characters that corrupt hashes, keys, and audit trails.

Filter evasion — hiding disallowed content in plain sight.

boundaryguard is a focused, dependency-free tool for the detection and removal of this character class. It was extracted from the adversarial hardening of a production verification system — where a security audit found invisible-character bugs in provenance and metadata handling — and is shipped with a test corpus of published attack samples.

⚠️ Scope: boundaryguard detects and removes invisible-character obfuscation. It is not a general-purpose SAST scanner, and it does not claim to be a complete defense against all prompt injection or all supply-chain attacks. It removes one well-defined attack class — thoroughly.

Install

pip install boundaryguard

Python 3.9+. No runtime dependencies.

CLI

# Scan a file or directory<br>boundaryguard scan path/to/file.py<br>boundaryguard scan --recursive .

# CI-friendly check (exit 0 clean, exit 1 findings, exit 2 error)<br>boundaryguard check --recursive .

# Explain characters in a string<br>boundaryguard inspect "hello\u202e"

# Sanitize a file (in place, or to a new file)<br>boundaryguard sanitize input.txt -o clean.txt<br>boundaryguard sanitize config.json --policy preserve_rtl

Example

$ boundaryguard scan suspicious.py<br>suspicious.py:4:14 U+202E RIGHT-TO-LEFT OVERRIDE (RLO) [bidi_format] render='\u202e'

1 invisible-Unicode hazard(s) found (policy=security).

Exit codes

Code<br>Meaning

No hazards found

Hazards found

Usage or I/O error

Drop boundaryguard check --recursive . into your CI and never merge invisible code again.

Python API

from boundaryguard import (<br>find_suspicious,<br>explain_character,<br>sanitize,<br>contains_bidi_controls,<br>contains_zero_width,<br>scan_path,

text = "user: \u202e admin"

# Detect<br>for hazard in find_suspicious(text):<br>print(hazard.escaped, hazard.name) # U+202E RIGHT-TO-LEFT OVERRIDE

# Explain any character<br>print(explain_character("\u202e")) # U+202E RIGHT-TO-LEFT OVERRIDE (RLO) [bidi_format]

# Sanitize<br>print(repr(sanitize(text))) # 'user: admin'

# File scanning with line/column<br>for fh in scan_path("src", recursive=True):<br>print(fh.path, fh.line, fh.column, fh.hazard.name)

Policies

Unicode bidi and zero-width characters aren't inherently malicious — they're required for legitimate multilingual text. boundaryguard ships two policies so you can be strict where it matters and permissive where it doesn't.

Policy<br>Bidi formatting controls<br>Bidi marks (LRM/RLM)<br>ZWSP / BOM<br>ZWNJ / ZWJ<br>C0 controls

security (default)<br>strip<br>strip<br>strip<br>strip<br>strip

preserve_rtl<br>strip<br>keep<br>strip<br>keep<br>strip

security — for identifiers, provenance keys, hashes, and anything machine-parsed or compared. Strict is safe.

preserve_rtl — for human-facing text in Arabic, Hebrew, Persian, and Urdu, where LRM/RLM and ZWNJ/ZWJ are needed for correct rendering. The dangerous formatting controls are still removed.

What it...

boundaryguard invisible strip unicode source security

Related Articles