
What Are Homograph Attacks and Lookalike Domains?
Look at these two domain names: apple.com and аррӏе.com. On most screens they are indistinguishable, yet they are completely different domains. The second one is written entirely in Cyrillic characters that happen to look like Latin letters. This trick is called an IDN homograph attack, and it is the most extreme form of a broader problem: lookalike domains that are registered to fool people into trusting a fake website or email. This article explains how homograph attacks work, the other kinds of lookalike domains attackers use, how browsers and email clients defend against them, how to detect lookalikes of your own brand with code, and what to do when you find one. It assumes a basic understanding of how non-ASCII domain names are stored; if that is new to you, read what internationalized domain names and Punycode are first.
What Is a Homograph Attack?
A homograph is a word that is written identically to another word but means something different. In domain security, a homograph attack uses characters from different writing systems that look identical, or nearly identical, to construct a domain that visually matches a legitimate one.
The enabling technology is Internationalized Domain Names (IDNs). IDNs let people register domains in scripts such as Cyrillic, Greek, Arabic, Chinese, and Devanagari. That is a genuine good: billions of people do not use the Latin alphabet. But Unicode contains many characters that look alike across scripts. These are called confusables. A few classic examples:
| Looks like | Actual character | Unicode code point | Script |
|---|---|---|---|
| a | а | U+0430 | Cyrillic |
| e | е | U+0435 | Cyrillic |
| o | о | U+043E | Cyrillic |
| o | ο | U+03BF | Greek |
| p | р | U+0440 | Cyrillic |
| c | с | U+0441 | Cyrillic |
| x | х | U+0445 | Cyrillic |
| i | і | U+0456 | Cyrillic |
| l | ӏ | U+04CF | Cyrillic |
Behind the scenes, DNS only carries ASCII. An IDN is converted to an ASCII form starting with xn-- using Punycode. So the domain that looks like paypal.com but uses a Cyrillic а is actually registered and resolved as:
pаypal.com -> xn--pypal-4ve.com
аррӏе.com -> xn--80ak6aa92e.com
The registry sees two completely different strings from the originals. The user, if the browser or email client shows the Unicode form, sees the brand they trust.
A Brief History
The idea was described in the early 2000s, and in 2017 security researcher Xudong Zheng demonstrated it vividly by registering xn--80ak6aa92e.com, which several major browsers at the time displayed as "apple.com" in the address bar, complete with a valid HTTPS certificate. Browser vendors tightened their display rules in response, and today a domain like that is typically shown in its xn-- form. The attack has not disappeared, though; it has shifted to places with weaker defenses, such as email display names, chat apps, documents, and mixed-script tricks that some display policies still allow.
Other Kinds of Lookalike Domains
Homographs get the headlines, but most lookalike domains in real phishing campaigns use plain ASCII. Attackers pick whatever technique is cheapest and most likely to work.
| Technique | Example for example.com | How it fools people |
|---|---|---|
| IDN homograph | exаmple.com (Cyrillic а) | Pixel-identical characters from another script |
| Character substitution | examp1e.com, rnicrosoft.com | 1 for l, rn for m, 0 for o, vv for w |
| Typosquatting | exmaple.com, exampel.com | Common typing mistakes |
| Combosquatting | example-login.com, example-support.net | Brand plus a plausible word |
| TLD swap | example.co, example.cm | Same name, different or near-miss TLD |
| Subdomain trick | example.com.account-verify.net | The real brand appears first, but the registered domain is at the end |
| Bitsquatting | exampld.com | Relies on single-bit memory errors in devices |
Typosquatting and combosquatting have their own dedicated guides: see what typosquatting is for misspelling-based domains and what cybersquatting is for the broader practice of registering domains that exploit someone else's brand.
The subdomain trick deserves special mention because it needs no special characters at all. Readers scan from left to right, see the brand name, and stop reading. The domain that actually matters, the registered domain, is the last two labels: account-verify.net.
What Attackers Use Lookalike Domains For
- Credential phishing: a fake login page for a bank, email provider, or SaaS tool.
- Business email compromise: emails from
ceo@examp1e.comasking finance staff to change bank details or pay an invoice. - Malware delivery: fake software download pages or update prompts.
- Ad and affiliate fraud: diverting traffic intended for a brand.
- Fake support: lookalike support sites with phone numbers that lead to scammers.
A lookalike domain can easily obtain a valid TLS certificate, because certificate authorities validate control of the domain, not whether it resembles a brand. The padlock icon tells you the connection is encrypted, not that the site is legitimate.
How Browsers and Email Clients Defend Against Homographs
Browser IDN Display Policies
Modern browsers decide, label by label, whether to show the Unicode form or the xn-- Punycode form. The exact rules differ by browser and change over time, but common checks include:
- Mixed scripts: a label mixing Latin and Cyrillic, for example, is shown as Punycode.
- Whole-script confusables: a label written entirely in Cyrillic characters that all look like Latin letters, such as
аррӏе, is shown as Punycode, particularly for TLDs that are not associated with that script. - Skeleton comparison: some browsers compare the label's "skeleton" (a normalized form based on Unicode's confusable mappings) against a list of popular domains and fall back to Punycode on a match.
- Disallowed characters: certain invisible or deceptive characters are never displayed in Unicode.
Chromium documents its algorithm publicly. Firefox has a similar policy and also offers the network.IDN_show_punycode setting in about:config, which forces all IDNs to be displayed as Punycode. That is a reasonable choice for administrators and security-conscious users who rarely visit non-Latin domains.
Registry Rules
Registries reduce the risk at registration time. ICANN's IDN guidelines and registry policies typically:
- Restrict each label to characters from a single script, or to approved script combinations, per TLD.
- Publish IDN tables listing which characters are allowed.
- Use variant rules, where visually equivalent names are blocked or bundled to the same registrant.
These rules help a lot, but they vary by TLD, and whole-script confusables can still be legal registrations.
Email Clients
Email is the weak spot. Many clients display only the sender display name by default, which can contain any text at all, including a perfect copy of a brand name. Even when the address is visible, few clients apply browser-style IDN display rules to email addresses. Combine a homograph or ASCII lookalike sending domain with a convincing display name and the message looks authentic. Authentication standards such as SPF, DKIM, and DMARC prove which domain sent a message, but an attacker can set up all three for their lookalike domain, so a pass does not mean the domain is the one you think it is.
How to Detect Homographs and Lookalikes with Code
Inspect a Suspicious Domain
This Python script, which uses only the standard library, reports which scripts each label uses, flags mixed-script labels, lists every non-ASCII character with its Unicode name, and prints the Punycode form:
import sys
import unicodedata
def script_of(ch):
if ch.isascii():
return "LATIN" if ch.isalpha() else "COMMON"
name = unicodedata.name(ch, "UNKNOWN")
return name.split(" ")[0] # e.g. LATIN, CYRILLIC, GREEK
def analyze(domain):
ascii_form = domain.encode("idna").decode("ascii")
for label in domain.rstrip(".").split("."):
scripts = {script_of(c) for c in label} - {"COMMON"}
flag = "MIXED SCRIPTS" if len(scripts) > 1 else "single script"
print(f"{label!r}: {sorted(scripts)} -> {flag}")
for c in label:
if not c.isascii():
print(f" U+{ord(c):04X} {unicodedata.name(c, '?')}")
print(f"ASCII (Punycode) form: {ascii_form}")
for d in sys.argv[1:]:
analyze(d)
print()
Running it against a mixed-script lookalike produces:
'pаypal': ['CYRILLIC', 'LATIN'] -> MIXED SCRIPTS
U+0430 CYRILLIC SMALL LETTER A
'com': ['LATIN'] -> single script
ASCII (Punycode) form: xn--pypal-4ve.com
The script-detection shortcut (taking the first word of the Unicode character name) is a simplification that works well for common scripts. For production use, Unicode Technical Standard #39 defines proper confusable detection, and libraries that implement it are available for most languages. Python's built-in idna codec follows the older IDNA2003 rules; the third-party idna package implements IDNA2008 if you need strict conformance.
Generate and Check Homograph Variants of Your Brand
To find homographs of your own brand that someone may have registered, generate variants using a small confusables map and check whether each one resolves in DNS:
import itertools
import socket
CONFUSABLES = {
"a": ["а"], # U+0430 CYRILLIC SMALL LETTER A
"c": ["с"], # U+0441 CYRILLIC SMALL LETTER ES
"e": ["е"], # U+0435 CYRILLIC SMALL LETTER IE
"o": ["о", "ο"], # U+043E Cyrillic o, U+03BF Greek omicron
"p": ["р"], # U+0440 CYRILLIC SMALL LETTER ER
"x": ["х"], # U+0445 CYRILLIC SMALL LETTER HA
"y": ["у"], # U+0443 CYRILLIC SMALL LETTER U
"i": ["і"], # U+0456 CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
}
def variants(label, max_swaps=1):
positions = [i for i, ch in enumerate(label) if ch in CONFUSABLES]
for n in range(1, max_swaps + 1):
for combo in itertools.combinations(positions, n):
choices = [CONFUSABLES[label[i]] for i in combo]
for repl in itertools.product(*choices):
chars = list(label)
for i, r in zip(combo, repl):
chars[i] = r
yield "".join(chars)
def check(brand, tld="com"):
for v in sorted(set(variants(brand))):
ascii_name = f"{v}.{tld}".encode("idna").decode("ascii")
try:
socket.getaddrinfo(ascii_name, None)
status = "RESOLVES"
except socket.gaierror:
status = "no DNS"
print(f"{ascii_name:30} {status}")
check("example")
A domain that does not resolve may still be registered, so for anything interesting, confirm registration with RDAP:
curl -sL -o /dev/null -w "%{http_code}\n" https://rdap.org/domain/xn--pypal-4ve.com
The -L flag follows the redirect from rdap.org to the registry's RDAP server. A 200 means the registry has a record; a 404 usually means the name is not registered.
Use dnstwist for Broad Coverage
The open-source tool dnstwist generates many classes of lookalikes at once, including homographs, typos, bitsquats, and TLD swaps, and can show which are registered:
pip install dnstwist
dnstwist --registered example.com
dnstwist --registered --format csv example.com > lookalikes.csv
Watch Certificate Transparency Logs
Every publicly trusted TLS certificate is logged in Certificate Transparency (CT) logs. Phishing sites almost always get certificates, so CT is an early warning system. The crt.sh service lets you search logs with a SQL-style wildcard:
curl -s "https://crt.sh/?q=%25example%25&output=json" \
| jq -r '.[].name_value' | sort -u
This lists every logged certificate name containing "example". Filter out your own domains and review the rest regularly. Note that crt.sh can be slow or rate-limited for very common terms.
How to Protect Your Organization
For brand owners:
- Monitor continuously using dnstwist, CT log searches, or a commercial brand protection service.
- Defensively register the most dangerous variants, especially obvious homographs and typos in your main TLDs. You cannot register everything, so prioritize.
- Publish strict DMARC (
p=reject) on your real domains, so attackers cannot spoof your exact domain and are forced onto lookalikes, which are easier to spot and block. - Act on abusive registrations quickly. Report phishing to the registrar's abuse contact and the hosting provider; for longer-term recovery, use dispute processes such as the UDRP.
For users and staff:
- Use a password manager. It autofills only on the exact domain it saved, so it will not fill your password into
exаmple.com. That silent refusal is one of the best homograph detectors there is. - Use phishing-resistant MFA such as passkeys or hardware security keys, which are bound to the real domain and will not authenticate to a lookalike. The same advice applies to registrar accounts; see how to secure your domain registrar account with 2FA.
- Navigate directly using bookmarks or typed addresses rather than links in emails.
- Read the registered domain, the part immediately before the TLD, not the beginning of the hostname.
- Flag external senders. Configure your mail gateway to tag external email and to flag sender domains that are confusable with your own.
Homograph Attacks FAQ
They are much harder in address bars, because modern browsers show suspicious IDNs as Punycode. But they remain effective in email display names, chat apps, documents, and anywhere text is rendered without IDN display rules.
The xn-- form is the ASCII encoding of an internationalized domain name. Browsers show it instead of the Unicode form when the name mixes scripts, looks confusable with a Latin name, or otherwise fails their display policy.
No. Certificate authorities verify that the requester controls the domain, not that it is legitimate or unrelated to a brand. A lookalike domain can have a perfectly valid certificate and padlock.
Often yes, subject to each registry's IDN rules. Many brands defensively register the most dangerous variants. Some registries bundle or block visual variants, so availability depends on the TLD.
Password managers match the exact saved domain. If you land on a lookalike, the manager will not offer to fill your credentials, which is a strong warning that something is wrong.
A homograph uses characters from other scripts that look identical to the real ones, so the name looks correct. Typosquatting uses ordinary characters arranged as a likely typing mistake, so the name is visibly different if you read carefully.
If you rarely visit sites with non-Latin domain names, it is a reasonable hardening step. In Firefox you can set network.IDN_show_punycode to true. If you regularly use IDNs, rely on the default display policy instead.
Conclusion
Homograph attacks exploit a gap between what people see and what computers resolve. A single Cyrillic letter turns a trusted brand into an attacker's domain, and the user cannot tell the difference by looking. Browsers have narrowed that gap in the address bar, but lookalike domains of every kind, from Unicode homographs to simple misspellings and misleading subdomains, remain one of the most common building blocks of phishing.
The good news is that the strongest defenses are not visual at all. Password managers and phishing-resistant MFA check the exact domain, strict DMARC forces attackers off your real domain, and automated monitoring of DNS and Certificate Transparency logs lets you spot lookalikes of your brand early. Combine those controls with prompt takedown requests, and lookalike domains become a manageable risk instead of an invisible one.
Here are some useful references for going deeper on homograph attacks and lookalike domains:
- Unicode Consortium: UTS #39: Unicode Security Mechanisms — defines confusable characters, skeletons, and mixed-script detection.
- Chromium: IDN in Google Chrome — how Chrome decides whether to show Unicode or Punycode for a domain.
- RFC 5890: Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework — the IDNA2008 framework behind IDNs.
- RFC 3492: Punycode — the encoding that turns Unicode labels into xn-- ASCII labels.
- Unicode Consortium: UTR #36: Unicode Security Considerations — background on visual spoofing and how to mitigate it.


