July 31, 2026
Bypassing Account Sign-up Restrictions with a Unicode Character
It’s been a while since I put a writeup up here, so I’m dusting off one of my favorites. The target was a user-management / identity…

By ͏ ͏Dukrov 🍏
2 min read
It's been a while since I put a writeup up here, so I'm dusting off one of my favorites. The target was a user-management / identity platform that a lot of apps bolt on for their login and signup flows. I'm keeping it nameless, but the pattern is general enough that it doesn't matter.
The platform offers an Account Domain Restriction control: from the environment settings you can allow or deny sign-ups based on the email domain a user comes from. Two common ways teams use this:
It's a security control. Customers rely on it to gate who gets in.
The bug
The restriction check compares the domain in your email against a blocklist as a literal string. So if blockeddomain.com is blocked, blockeddomain.com gets rejected. But blockeddomaİn.com doesn't. That İ is a latin capital letter I with a dot above. To the blocklist it's just some other character, so blockeddomaİn.com is not blockeddomain.com and the sign-up sails straight through the filter.
The interesting part is what happens next. Once the check passes, the address flows downstream into account creation and email dispatch and somewhere in that pipeline it gets case-folded/normalized. İ collapses back to a plain i, the address becomes blockeddomain.com again, and the verification code lands in the real inbox. You confirm, and you've got an account in an app that was configured to never let you have one.
Root cause
This isn't really a "unicode is scary" bug. It's a disagreement between two components about what the same email is. The enforcement layer sees the raw string blockeddomaİn.com and decides it's not blocked. The normalization / delivery layer folds it down to blockeddomain.com and treats it as the real, deliverable address.
Both are internally consistent. The vulnerability lives in the gap between them, the classic pattern where validation and use operate on two different representations of the "same" value. Anywhere a system checks one form of an input and then acts on a normalized form of it, that seam is worth poking.
The İ → i collapse is the well-worn example (the Turkish dotted-I problem), but the general failure is normalization-after-validation. If your allow/deny decision runs on a string that later gets canonicalized, an attacker only needs a character that survives the check and dies during normalization.
Steps to reproduce
Assume blockeddomain.com is a domain you actually control a mailbox at, and that it's on the deny list.
- In the admin settings, enable domain restriction e.g. Deny all public domains.
- From the app, try to sign up with a normal address (e.g.
you@blockeddomain.com). You get the expected "contact your admin" rejection. - Retry with the same address, but swap a letter for a homoglyph
you@blockeddomaİn.com(that's U+0130 in place of thei). - Check your inbox. The sign-up / login code arrives at your real mailbox, and you can complete registration restriction bypassed.
Tip
Handy reference for pulling normalization-friendly characters: 0xacb's normalization table.
Impact
Let me keep this honest, it's a security-control bypass, not an account takeover or a data leak on its own. What it defeats is the guarantee customers think they bought: "only these domains can register" or "no public email addresses." A tenant that locked signups to a corporate domain, or one that banned free-mail accounts to cut down on abuse, can be walked around by anyone with an inbox and one substituted character. The attacker uses their own real mailbox the whole time, so there's no mail-server trickery required, just a filter that trusts a string it never canonicalized.
Where it gets more interesting is as a chain link. Domain gating is often the first trust assumption everything downstream leans on internal-only apps, auto-provisioning based on domain, "employees are trusted" logic. Break the gate cheaply and whatever sat behind it inherits the problem.
Remediation
Normalize before you validate, not after. Canonicalize the email Unicode normalization (NFKC), case-folding, and IDNA/Punycode handling for the domain and run the allow/deny decision against that canonical form, which is also the form you store and deliver to. One representation, checked and used consistently. No seam, no bypass.