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.


Prevention & Best Practices

1. Always Normalize Before Validating User-Supplied Strings

Whenever you validate a string that may contain Unicode — email addresses, usernames, URLs — apply normalization first:

// Recommended pattern for email handling
function normalizeEmail(raw) {
  // Step 1: Unicode normalization (NFKC collapses compatibility characters)
  const nfkc = raw.normalize('NFKC');
  // Step 2: Lowercase and trim
  const clean = nfkc.toLowerCase().trim();
  // Step 3: Now validate
  if (!EMAIL_REGEX.test(clean)) {
    throw new Error('Invalid email address');
  }
  return clean;
}

NFKC (Compatibility Decomposition followed by Canonical Composition) is the strongest normalization form for security contexts because it collapses fullwidth, halfwidth, and other compatibility variants into their canonical ASCII equivalents.

2. Keep Authentication Dependencies on a Monitored Update Track

Authentication libraries are high-value targets. Pin to a minimum patch version and subscribe to the library's security advisories:

  • GitHub: Watch the next-auth repository → Security advisories
  • npm audit: Run npm audit in CI on every pull request
  • Trivy / Grype: Integrate SCA scanning into your pipeline to catch CVEs in transitive dependencies

3. Use a Software Composition Analysis (SCA) Tool

Static analysis and SCA tools can detect vulnerable dependency versions before they reach production. Trivy flagged this exact CVE (CVE-2026-73420) against the next-auth entry in package-lock.json.

4. Apply Defense-in-Depth at the Application Layer

Even with a patched library, consider adding an application-level email normalization step before passing addresses to next-auth:

// pages/api/auth/[...nextauth].ts
import NextAuth from 'next-auth';
import EmailProvider from 'next-auth/providers/email';

export default NextAuth({
  providers: [
    EmailProvider({
      // Normalize before next-auth ever sees the address
      normalizeIdentifier(identifier: string): string {
        return identifier.normalize('NFKC').toLowerCase().trim();
      },
    }),
  ],
});

5. Relevant Security Standards

  • OWASP Authentication Cheat Sheet — covers identifier normalization requirements
  • CWE-178: Improper Handling of Case Sensitivity (Unicode normalization order)
  • CWE-20: Improper Input Validation
  • RFC 5321 / RFC 5322: Email address syntax standards
  • Unicode Security Considerations (UTR #36): Guidance on homoglyph and normalization attacks

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.


References

Frequently Asked Questions

What is a Unicode homoglyph email bypass?

It is an attack where an adversary substitutes a Unicode character that looks visually identical to a standard ASCII character (here, a lookalike for "@") so that a validator written for ASCII accepts the address, while downstream processing resolves it to a different canonical address.

How do you prevent Unicode homoglyph email bypass in JavaScript?

Always apply Unicode normalization (e.g., NFKC or NFC via `str.normalize('NFKC')`) to any user-supplied string before running format validation, so lookalike characters are collapsed to their ASCII equivalents before the check runs.

What CWE is Unicode homoglyph email bypass?

It maps primarily to CWE-178 (Improper Handling of Case Sensitivity), which covers failures to account for Unicode equivalence and normalization, and secondarily to CWE-20 (Improper Input Validation).

Is RFC 5321 email format validation enough to prevent this bypass?

No. Standard regex or RFC-based validators operate on the raw byte/character sequence. If a homoglyph "@" is present, the string may still match the pattern while being semantically different from the intended address. Normalization must precede validation.

Can static analysis detect Unicode homoglyph email bypass?

Yes. Tools like Trivy (which flagged this CVE) and Semgrep rules targeting email normalization order can surface this class of issue. Orbis AppSec's automated scanner detected this exact pattern in the next-auth dependency and opened a remediation PR automatically.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #16

Related Articles

critical

How Missing Rate Limiting Happens in Express.js Authentication Endpoints and How to Fix It

A critical security vulnerability was discovered in the Apple Store API implementation where three authentication endpoints (`/auth/login`, `/auth/refresh`, `/auth/reset`) lacked rate limiting protection. This allowed unlimited authentication attempts from a single IP address, enabling credential stuffing and brute force attacks. The fix implements an in-memory rate limiter that restricts each IP to 5 requests per 15-minute window.

high

How CORS Misconfiguration Happens in FastAPI and How to Fix It

A FastAPI application serving as a MyShows proxy was configured to allow all origins with credentials enabled, creating a dangerous CORS misconfiguration that could let any malicious website silently harvest authentication tokens. The fix was a single-line change — setting `allow_credentials=False` — but the implications of leaving it unchecked were significant. This post breaks down exactly how the vulnerability works, why FastAPI's behavior makes it subtler than it first appears, and how to co

high

How Weak bcrypt Salt Rounds Happen in Node.js and How to Fix It

A critical password hashing weakness was discovered in the authentication controller where bcrypt was configured with only 10 salt rounds instead of the recommended minimum of 12. This configuration made user passwords significantly more vulnerable to brute-force attacks if an attacker gained access to the password hash database. The fix was a simple but impactful one-line change that doubles the computational cost required to crack passwords.

critical

How broken authentication happens in Node.js Express APIs and how to fix it

A critical authentication bypass in the `/api/posts` endpoint allowed any unauthenticated user to create, update, or delete posts without verification. The POST endpoint had zero authentication checks, while PUT and DELETE endpoints used a trivially bypassable username comparison that attackers could forge by simply including the target username in their request body. The fix validates user identity by looking up the userId in the database before any post operations.

medium

How Insufficient Password Hashing Cost Factor Happens in Node.js and How to Fix It

A bcrypt password hashing implementation in the User.js model was using a cost factor of 10, which falls below OWASP's 2024 recommendation of 12 for applications handling sensitive data. This fix upgrades the salt rounds from 10 to 12, increasing the computational work required to crack passwords by approximately 4x, significantly improving protection against brute-force attacks on this e-commerce platform.

critical

How Missing Rate Limiting happens in Express.js and how to fix it

Two public API endpoints in `server.js` — `/api/health` and `/api/contact` — were exposed without any rate limiting middleware, allowing attackers to exhaust server resources or spam an SMTP server with unlimited requests. The fix adds rate limiting to both endpoints, with stricter controls on the resource-intensive `/api/contact` route that triggers email sending operations. This change closes a directly exploitable denial-of-service vector in a production web service.