Unicode Tricks Let Malicious Python Code Bypass Code Review

A detailed analysis shows how subtle Unicode manipulations allow code to pass human review while executing entirely different logic. The first technique replaces Latin characters with visually identical Cyrillic or other script letters inside identifiers, such as using Ukrainian 'і' instead of Latin 'i' in an is_admin variable. Python treats these as distinct names because NFKC normalization does not map Cyrillic to Latin. The second technique inserts bidirectional override characters that reorder text for the compiler while the editor displays the intended order. The third hides zero-width characters inside string literals to break comparisons and searches. A compact Python auditor using the tokenize module and explicit character sets detects all three classes of characters. The article recommends adding such checks to CI pipelines and configuring linters including ruff and flake8 to reject suspicious commits.

HabrTranslated from Russian

Read at source

A subtle but powerful class of attacks allows source code to pass human review while executing completely different logic. The root cause lies in the gap between how fonts render Unicode characters and how the Python interpreter reads the underlying bytes.

The first technique uses homoglyphs. An attacker can declare is_admin = False followed by a second assignment that looks identical but actually uses the Ukrainian letter і (U+0456) instead of Latin i (U+0069). The review sees a single variable being set to True, yet the interpreter creates two separate identifiers. The same substitution works for function names such as validate_token, causing the wrong implementation to run in production.

Python normalizes identifiers with NFKC, which collapses some visually similar characters but leaves Cyrillic letters untouched. Consequently, the attack remains effective in real codebases.

The second technique relies on bidirectional override characters (RIGHT-TO-LEFT OVERRIDE U+202E and related controls). These characters are required for Arabic and Hebrew text, yet they also allow an attacker to reorder source lines visually. A comment that appears harmless on screen can actually contain executable statements once the compiler ignores the display order. The technique became widely known in 2021 as the Trojan Source attack and affects nearly every mainstream programming language.

The third, simpler method inserts zero-width characters (U+200B, U+2060, etc.) inside string literals. The string 'pass​word' has length nine and will never equal the expected value, yet the difference is invisible to the naked eye and defeats both manual inspection and simple grep searches.

A compact detection script walks the source with Python’s tokenize module and separately scans for bidirectional and zero-width characters. Checking only identifier tokens prevents false positives from comments and string data. The same logic is available as built-in rules in ruff and flake8, while gitleaks can block commits containing the dangerous characters.

Teams are advised to run the check across existing repositories, integrate it into CI pipelines, and treat any intentional insertion of these characters as a serious red flag during incident review.

Meridian digestThe week's most consequential security stories, distilled into one briefing.See the digest

More in Supply Chain & Open Source

Passwordless Kubernetes Image Pulling with Artifact Keeper via ServiceAccount Tokens
Malicious Code Injected into LiteLLM Open Source AI Package via Supply Chain Attack
GhostAction Campaign Compromises 790 GitHub Repositories via Malicious Workflows