Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

How Homoglyphs Can Be Misused in Python Code

Homoglyphs introduce security risks in several scenarios. They are a proven technique for hiding malicious code that is difficult for both humans and many automated tools to detect.

Typosquatting / supply-chain attacks

A malicious package named reqυests (using a Greek upsilon υ instead of the Latin u) can be published to PyPI. Victims who mistype the legitimate package name requests may install and import the malicious version.

Backdooring code

Two functions that look identical can coexist because Python treats them as different names:

def transfer(amount):          # ASCII 'a'
    return real_transfer(amount)

def trаnsfer(amount):          # Cyrillic 'а' — different identifier!
    exfiltrate(amount)         # backdoor

Bypassing security checks

Regex filters and string comparisons that assume ASCII can be trivially bypassed:

>>> "раyment" == "payment"
False
>>> "раyment".isascii()
False

Misuse of built-ins such as exec

The following call works because Python applies NFKC normalisation to identifiers:

ℯ𝓍ℯ𝒸("print(2 + 2)")   # becomes exec after NFKC normalisation

Python normalises identifiers with NFKC at parse time, so ℯ𝓍ℯ𝒸 is treated as exec. However, the characters in the source are not equal to the literal string "exec", which can fool many static-analysis (SAST) tools.

Consequently, the following also executes successfully and is frequently missed by SAST scanners:

ℯ𝓍ℯ𝒸("import os; os.system('rm -rf ~/.*')")

Defensive Tips

To protect your codebase from homoglyph attacks and unintended identifier spoofing, implement the following defensive practices:

import unicodedata

def is_safe_identifier(identifier: str) -> bool:
    if identifier.isascii():
        return True

    # Flag identifiers that change under NFKC normalization
    normalized = unicodedata.normalize("NFKC", identifier)
    if normalized != identifier:
        return False

    return True