Unicode Addresses and Homograph Attacks: When Two Addresses Look Identical

« Blog · By

For decades email addresses were built from a narrow set of characters: Latin letters, digits, a handful of punctuation marks. Anyone whose name is not written in Latin script had to transliterate it — a small daily imposition for a large part of the world. Two extensions fixed that, and both bring a security problem most mail clients still do not solve.

Two extensions, not one

An address has two parts, and they were internationalised separately.

The domain part after the @ has been allowed to carry characters beyond the Latin alphabet since the early 2000s. Technically this happens by transcription: müller.de becomes xn--mller-kva.de internally. That transcription is called Punycode, it is unambiguously reversible, and DNS only ever sees the ASCII form. Which is why such domains work everywhere.

The local part before the @ is the newer and harder extension. There is no transcription for it — real UTF-8 characters sit in the message. For that to work, every server involved has to support the SMTP extension SMTPUTF8. Missing at a single point in the chain, the message is refused.

The difference matters in practice: an address like info@müller.de is unproblematic. An address like müller@company.com is not — it can fail in transit at a server you neither know nor control.

Where it turns unpleasant

Different writing systems contain characters that look the same and are not. The Cyrillic а (U+0430) and the Latin a (U+0061) render identically in virtually every typeface. The same goes for е and e, о and o, р and p, с and c.

How both are displayed in the inbox: billing@northbank.com billing@nоrthbank.com What DNS actually looks up: northbank.com xn--nrthbank-nbh.com One single character is swapped — the o. Two different domains, two different owners. The upper row is all the recipient ever gets to see.
The two addresses are indistinguishable on screen. The difference only becomes visible when the transcription is shown — and very few clients do that.

Why browsers solved this better

In a browser's address bar this attack is largely dealt with, by a rule that looks crude at first glance: if a domain name contains characters from several writing systems, or the writing system does not match the configured language, the browser displays the Punycode form. A convincing lookalike domain then visibly becomes xn--….

Mail clients mostly do not do this. They show the sender address as written — often only the display name, and not the address at all. The protection you are used to from the browser simply does not exist here.

What this gets used for

  • Senders that look like a business partner. Combined with an ongoing case and a changed bank account, this is the classic invoice redirection.
  • Domains that are fully registered and equipped with SPF, DKIM and DMARC. This is important to grasp: such a message is technically correctly authenticated. It comes from the domain it claims — only that is a different domain from the one the reader has in mind. No checking mechanism raises a flag here, because none has anything to object to.
  • Links in the message body pointing at the twin domain, where a genuine-looking login page is waiting.

The second point is the most important and is regularly overlooked. A green tick on sender authentication says nothing about whether the domain is the right one. It says only that the domain matches itself.

What helps

When reading: the display name is worthless and the address is nearly so — what decides is how it resolves. If a payment demand leaves you unsure, paste the address into a text field and check that every character is what it claims to be. More practical day to day is the rule that applies anyway: a changed bank account is not confirmed by email but over a number you already have. Further markers by which such messages can be recognised are covered in a separate article.

When building forms: hand-written validation patterns for addresses fail here in both directions. They either reject valid international addresses — locking out real users — or accept everything. The check that actually holds is a different one anyway: send a confirmation message to the address. Validating only the string validates the wrong thing.

When running a brand: the obvious defence — registering all similar domains yourself — still half works for Latin confusions and no longer works for Unicode. The number of visually identical spellings is too large to buy. What does help is monitoring: there are public logs of every newly issued TLS certificate, and a domain imitating your name shows up there as soon as somebody puts it into service.

And your own address?

If you run a domain with special characters, set up the ASCII spelling as a second domain and forward it. Not because of the technology — that works — but because of the people who have to read the address out over the phone.

And for the local part before the @: unless you know that all your counterparties support SMTPUTF8, an address made of Latin characters is the choice that reliably arrives. That is not a recommendation anyone should be satisfied with — it is the state of implementation.