Back to Blog
critical SEVERITY8 min read

How Unicode Homoglyph Email Bypass happens in Next.js (Auth.js) and how to fix it

CVE-2026-73420 is a critical authentication bypass vulnerability in Auth.js (next-auth) where the email normalizer validates an address before applying Unicode normalization, allowing an attacker to craft an email containing a Unicode homoglyph that looks like "@" to slip past validation and impersonate another user. The fix upgrades next-auth from 4.24.13 to 4.24.15 (and 5.0.0-beta.32 for the beta line), ensuring normalization happens before validation so lookalike characters are resolved to th

O
By Orbis AppSec
Published August 26, 2026Reviewed August 26, 2026

Answer Summary

CVE-2026-73420 is a critical authentication bypass in Auth.js / next-auth (CWE-178: Improper Handling of Case Sensitivity / Unicode normalization order). The email normalizer validated the address before applying Unicode normalization, so a homoglyph character visually identical to "@" could pass the format check while resolving to a different canonical address after normalization, enabling account takeover. The fix is to upgrade next-auth to 4.24.15 (v4) or 5.0.0-beta.32 (v5 beta), which reorders the pipeline so normalization always precedes validation.

Vulnerability at a Glance

cweCWE-178 (Improper Handling of Case Sensitivity) / CWE-20 (Improper Input Validation)
fixUpgrade next-auth to 4.24.15 / 5.0.0-beta.32, which normalizes the email string before validation
riskAttacker registers or signs in with a homoglyph email that bypasses format validation, potentially impersonating a legitimate user and gaining unauthorized account access
languageJavaScript / TypeScript (Node.js)
root causeEmail format validation runs before Unicode normalization, so homoglyph "@" characters pass the validator but resolve to a different canonical address
vulnerabilityUnicode Homoglyph Email Bypass

Introduction

The package-lock.json file in a Next.js application is easy to overlook — it is auto-generated, rarely read by humans, and usually committed without ceremony. But locked inside it was a critical authentication vulnerability: CVE-2026-73420, a flaw in how Auth.js (the library powering next-auth) normalizes email addresses before sign-in.

The bug is subtle and dangerous. Auth.js's email normalizer was validating the address format before applying Unicode normalization. That ordering mistake means an attacker can submit an email like user@example.com — where (U+FF20, FULLWIDTH COMMERCIAL AT) is a Unicode lookalike for the standard @ (U+0040) — and the validator sees a string with no recognizable @ character, potentially treating it as valid under certain code paths while downstream processing resolves it to user@example.com, the address of a real user.

The fix: upgrade next-auth from 4.24.134.24.15 (and 5.0.0-beta.32 for the v5 beta line), which reorders the pipeline so normalization always precedes validation.


The Vulnerability Explained

What is a Homoglyph Attack?

Unicode contains thousands of characters that are visually indistinguishable — or nearly so — from common ASCII characters. The @ sign (U+0040) that separates the local part from the domain in an email address has multiple lookalikes in Unicode, including:

Character Unicode Code Point Name
@ U+0040 COMMERCIAL AT (standard)
U+FF20 FULLWIDTH COMMERCIAL AT
U+FE6B SMALL COMMERCIAL AT

A properly hardened email normalizer should call something equivalent to:

// Safe order: normalize FIRST, then validate
const normalized = rawEmail.normalize('NFKC').toLowerCase().trim();
if (!isValidEmail(normalized)) throw new Error('Invalid email');

But the vulnerable version of Auth.js did the opposite — it validated the raw input first, then normalized. Conceptually:

// VULNERABLE order (pre-fix behavior in next-auth 4.24.13)
if (!isValidEmail(rawEmail)) throw new Error('Invalid email');
const normalized = rawEmail.normalize('NFKC').toLowerCase().trim();
// Too late — a homoglyph @ already passed validation

The Concrete Attack Scenario

Consider an application that uses next-auth with an email sign-in provider (magic links or OTP). The target victim has the account alice@example.com.

  1. Attacker crafts the payload: alice@example.com — using U+FF20 FULLWIDTH COMMERCIAL AT instead of the standard @.
  2. Validation step (pre-fix): The validator inspects the raw string. Depending on the regex used, the string may pass (no standard @ found, so the local-part is treated as the entire string, or the regex matches the fullwidth variant as a non-@ character and passes a lenient check) or behave unexpectedly.
  3. Normalization step (post-validation, pre-fix): NFKC normalization converts @, producing alice@example.com.
  4. Session / token issued: Auth.js now has a normalized email alice@example.com — the real victim's address — and may issue a session or send a magic link to that address, effectively granting the attacker access to the victim's account.

The exact exploitability depends on the sign-in flow, but the root cause — validate-then-normalize instead of normalize-then-validate — creates a window where the identity of the email address is ambiguous between the validation and normalization steps.

Why This Is Critical

Email addresses are primary identity keys in most web applications. A bypass here is not a theoretical edge case — it is a direct path to account takeover. An attacker who can register or sign in as alice@example.com by submitting alice@example.com can:

  • Receive magic-link emails intended for the victim (if the mailer normalizes independently)
  • Inherit an existing account's data, permissions, and sessions
  • Bypass email-based MFA flows

The Fix

The remediation is a targeted dependency upgrade in package.json and package-lock.json. Here is the exact change:

package.json / package-lock.json — Version Pin

Before:

"next-auth": "^4.22.3"

After:

"next-auth": "^4.24.15"

And in the resolved lock entry:

-      "version": "4.24.13",
-      "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.13.tgz",
-      "integrity": "sha512-sgObCfcfL7BzIK76SS5TnQtc3yo2Oifp/...",
+      "version": "4.24.15",
+      "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.15.tgz",
+      "integrity": "sha512-NnjYtjrSOAx/TIVFGTX4IfI/9yHnNpi4B7FuLUwuV20v2Zxgr2OGP/...",

Sub-dependency: uuid Bumped to v11

The fix also updates the bundled uuid sub-dependency from 8.3.211.1.1:

-        "uuid": "^8.3.2"
+        "uuid": "^11.1.1"
-      "version": "8.3.2",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "version": "11.1.1",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz",

The uuid bump is a hardening improvement included in the patched release — v11 drops the legacy v1/v3 generators that had weaker entropy properties and aligns with the updated RFC 9562 UUID specification.

Why These Two Files?

package.json sets the minimum acceptable version (^4.24.15), preventing future npm install runs from ever resolving to the vulnerable 4.24.13. package-lock.json pins the exact resolved artifact and its SHA-512 integrity hash, ensuring that the specific .tgz downloaded from the registry is the patched one. Both changes together close the vulnerability at install time and at runtime.


Key Takeaways

  • Validate after normalizing, never before: The root cause of CVE-2026-73420 is a two-line ordering mistake — normalization came after validation in Auth.js's email pipeline. This single ordering error opened a critical authentication bypass.
  • Homoglyph attacks are practical, not theoretical: Unicode contains multiple @-lookalike characters (U+FF20, U+FE6B, etc.) that are trivially copy-pasteable. Any application accepting email addresses from untrusted input is potentially exposed if it skips pre-validation normalization.
  • package-lock.json integrity hashes matter: The fix updates both the version string and the SHA-512 integrity hash in package-lock.json, ensuring the exact patched artifact is fetched — not just a version that satisfies the semver range.
  • Sub-dependency hygiene counts: The uuid bump from 8.3.211.1.1 inside next-auth is a secondary hardening improvement. Transitive dependency updates in security patches are intentional and should not be reverted.
  • SCA scanning in CI catches this class of issue automatically: Trivy identified this CVE from the package-lock.json entry alone, before any manual code review. Integrating SCA into your pipeline means you get alerted — or auto-fixed — before vulnerable code ships.

How Orbis AppSec Detected This

  • Source: User-supplied email address submitted to the Auth.js sign-in endpoint (HTTP POST body parameter, typically email or identifier)
  • Sink: Auth.js's internal email normalizer function, which called the format validator on the raw input string before invoking Unicode normalization — allowing a homoglyph @ character to pass the format check and resolve to a different canonical address downstream
  • Missing control: Unicode normalization (NFKC) was absent from the pre-validation step; the normalizer only ran after the validator had already accepted the raw, potentially homoglyph-containing string
  • CWE: CWE-178 — Improper Handling of Case Sensitivity (Unicode normalization order); CWE-20 — Improper Input Validation
  • Fix: Upgraded next-auth from 4.24.13 to 4.24.15 in package-lock.json, which reorders the email pipeline so NFKC normalization precedes format validation

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-73420 is a reminder that authentication security is not just about algorithms and key lengths — it is also about the order of operations applied to user-supplied identifiers. A two-step pipeline (validate → normalize) that gets its steps reversed becomes a critical authentication bypass. The fix is a one-line version bump, but understanding why that bump matters is what separates a reactive patch from a durable security posture.

If your application uses next-auth, upgrade to 4.24.15 (v4) or 5.0.0-beta.32 (v5 beta) immediately. If you build email normalization logic yourself, always apply normalize('NFKC') before any format validation. And if you want your dependency tree scanned automatically for issues like this, Orbis AppSec has you covered.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #16

Related Articles

critical

How Hardcoded Secrets Compromise Authentication in JavaScript and How to Fix It

A critical vulnerability in `Tool/QuantumultX/Rewrite/RRSP.js` exposed hardcoded API authentication credentials—a TOKEN and UMID device identifier—directly in source code. Anyone with repository access could extract these credentials to impersonate the legitimate user and gain full account access to the RRTV API service. The fix replaced hardcoded secrets with empty placeholders, forcing users to manually configure credentials through secure channels.

critical

How origin validation bypass happens in Express.js and how to fix it

A `POST /changeData` route in `src/main/server/routes/index.js` guarded state-changing writes with an origin allowlist, but the guard was wrapped in an `if (origin && ...)` truthiness check. Any request that simply omitted both `Origin` and `Referer` — a one-line `curl` command, a local script, a background process — skipped validation entirely and modified application data. The fix removes the truthiness short-circuit so a *missing* header is now treated as a rejection, not a pass.

critical

How CSRF vulnerabilities happen in Node.js API clients and how to fix them

A critical CSRF vulnerability in `lib/client.js` allowed attackers to forge authenticated POST requests to `/remote-ssh/api/*` endpoints. The fix adds the `X-Requested-With: XMLHttpRequest` header to enable proper CSRF token validation, blocking malicious cross-site requests with a minimal one-line change.

critical

How User Enumeration Happens in Django Forms and How to Fix It

A critical user enumeration vulnerability in the volunteers application allowed attackers to systematically discover registered email addresses through distinct error messages in signup and password reset forms. The fix replaces specific error messages with generic ones, preventing information disclosure while maintaining application functionality.

critical

How Authentication Bypass Happens in Node.js WebSocket Services and How to Fix It

The HousePanel push notification service exposed GET and POST endpoints without any authentication checks, allowing unauthenticated attackers to send arbitrary push notifications to connected smart devices. This critical vulnerability was fixed by implementing mandatory token validation on all protected endpoints, ensuring only authenticated requests can trigger push operations.

critical

How Missing API Authentication Happens in Node.js and How to Fix It

The GitHub API integration in `src/github.mjs` was making unauthenticated requests, subjecting the application to GitHub's strict 60 requests/hour rate limit. This fix adds secure authentication token injection from environment variables using conditional header spreading, enabling authenticated requests with a much higher rate limit (5,000 requests/hour).