To a program, the Latin letter A and the Greek letter Alpha are different characters. To a person reading a screen, they can be the same shape. That gap between what the machine compares and what a human sees is the whole of CWE-1007.
The weakness: the product displays information or identifiers to a user, but the display mechanism does not make it easy to tell visually similar or identical glyphs apart. The user may misread a glyph and take an insecure action. MITRE classes it as a Base weakness that is not language or technology specific, with web based occurrences.
It matters to anyone who shows names, links or identifiers to people: web applications, forums, admin consoles, log viewers and package registries.
How it happens
MITRE's extended description gives three families of lookalikes.
- Same shape, different code. The lowercase "l" (ell) and the uppercase "I" (eye) have different character codes but can render identically, depending on the font.
- Different alphabets. Latin capital "A" and Greek capital "Alpha" are distinct to a program and can display the same way.
- Accent marks. A letter with a grave accent and the same letter with an acute accent can look nearly alike at a glance.
An attacker needs only one place where a human decides based on how a string looks. MITRE highlights two uses.
First, phishing. The attacker supplies a link to a hostname that looks like one the victim trusts. The victim reads the address bar, sees what they expect, and proceeds.
Second, hiding in plain sight. An adversary creates a back door username visually similar to a regular user's name. When an administrator reviews logs, the two are hard to tell apart, so the malicious account blends in. Homoglyph tricks can also forge log entries by the same route.
The observed CVEs on the MITRE page show how this appeared in real products:
- CVE-2013-7236: a web forum allowed impersonation of users with homoglyphs in account names.
- CVE-2017-5015: a web browser did not convert hyphens to punycode, allowing internationalized domain name spoofing in URLs.
- CVE-2012-0584: improper character restriction in URLs in a web browser.
- CVE-2009-0652: an incomplete denylist that did not include homoglyphs of the slash and question mark characters in URLs.
A small, defensive demonstration of the problem in Python. These two strings print the same in many fonts:
latin = "paypal"
mixed = "pаypal" # the second letter is Cyrillic, not Latin a
print(latin == mixed) # False
print(mixed.isascii()) # False, which is a useful signal
What an attacker gains
MITRE lists effects on integrity and confidentiality, in the form of deception:
- A user may be redirected to a malicious website because they believe the URL belongs to a trusted domain.
- Log entries and account lists can be forged or obscured using homoglyphs in usernames.
- More generally, homoglyph manipulation undermines any decision where a human is the final check.
The common thread is trust. The attack does not break encryption or authentication. It persuades a person to authenticate to, or trust, the wrong thing.
How to find it
The MITRE record suggests manual dynamic analysis. If your product has user accounts, try submitting a username that contains homoglyphs. Then check whether links containing homoglyphs can be sent through email, web browsers or other channels your product touches.
Add a few more checks:
- Registration. Try to register a name that matches an existing one except for a lookalike character. Does the system accept it?
- Display. Look at how identifiers are shown to administrators. Are they in a font that separates ell, eye and the digit one?
- Mixed scripts. Search your user table for names that mix scripts, such as Latin with Cyrillic. Legitimate cases exist, but most are worth a look.
- Logs. Check whether your log viewer renders non-ASCII characters in names without any marking.
- Dependencies. Package names are identifiers users type or copy. A package named with a lookalike character can pass a casual review.
How to fix it
MITRE gives two implementation mitigations aimed at the display and delivery side.
- Use a browser that shows Punycode for internationalized domain names in the address and status bars, or that color codes the scripts in URLs. Firefox and Chrome display IDNs as Punycode if the top level domain does not restrict which characters can be used in domain names, or if labels mix scripts from different languages.
- Use an email client with strict filters that keeps messages mixing character sets out of the inbox. MITRE notes that Gmail, for one, prevents non-Latin characters in email addresses or links, flagging such messages and sending them to spam.
If you build the product rather than only use one, apply the same thinking in your own code:
- Normalize identifiers on input and compare the normalized form, so near duplicates collide.
- Restrict usernames to a defined character set, or reject names that mix scripts.
- Show identifiers in a font that separates confusable characters, and mark non-ASCII characters in admin views.
- Display the raw Punycode form of a hostname next to the friendly one in security sensitive screens.
- Make the confirmation step show the full, exact identifier, not an abbreviated one.
Try it yourself
Package names are identifiers too, and lookalikes can pass a casual review. This demo shows how malware and typosquat detection works for dependencies.
Click through it at your own pace, or open it full screen.
You can also run the free in-browser dependency scan at gold.safeguard.sh/scan. No login, the file stays on your machine, up to 100 dependencies.
Quick check
Why do homoglyphs bypass a plain string comparison check?
The strings are different at the character code level, so a program treats them as different. A person sees them as the same, so the human review step fails even though the program is working as designed.
How do homoglyphs help hide a back door account?
An attacker creates a username visually similar to a regular user's. Reviewing logs, an administrator has trouble telling the two apart.
What do Chrome and Firefox do to reduce the risk?
They display internationalized domain names as Punycode when the top level domain does not restrict allowed characters, or when labels mix scripts.