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.13 → 4.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.
- Attacker crafts the payload:
alice@example.com— using U+FF20 FULLWIDTH COMMERCIAL AT instead of the standard@. - 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. - Normalization step (post-validation, pre-fix): NFKC normalization converts
@→@, producingalice@example.com. - 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.2 → 11.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-authrepository → Security advisories - npm audit: Run
npm auditin 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.jsonintegrity hashes matter: The fix updates both the version string and the SHA-512 integrity hash inpackage-lock.json, ensuring the exact patched artifact is fetched — not just a version that satisfies the semver range.- Sub-dependency hygiene counts: The
uuidbump from8.3.2→11.1.1insidenext-authis 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.jsonentry 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
emailoridentifier) - 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-authfrom4.24.13to4.24.15inpackage-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.