Jul 23, 2026·6 min read·2 visits
Unauthenticated attackers can crash Auth.js applications using malformed authorization headers, while logical flaws in OAuth cookie validation allow cross-provider session replay attacks.
Auth.js (formerly NextAuth.js) contains a denial of service vulnerability due to an uncaught URIError in the getToken() token parser when processing malformed percent-encoded sequences in bearer tokens. Additionally, the library was vulnerable to session state confusion and replay attacks because OAuth check cookies (state, nonce, and PKCE) were not properly bound to specific providers, permitting cross-provider token reuse.
Auth.js (formerly NextAuth.js) is an open-source authentication library widely utilized in modern JavaScript frameworks including Next.js, SvelteKit, and SolidStart. It handles session management, token validation, and OAuth flows. Due to the placement of Auth.js inside server-side middleware and critical API request pipelines, vulnerabilities within its core parser expose a significant unauthenticated attack surface.
This advisory addresses two distinct security issues resolved in the same release cycle. The primary vulnerability is a Denial of Service (DoS) vector inside the getToken() helper function, classified under CWE-248 (Uncaught Exception) and CWE-20 (Improper Input Validation). The secondary flaw is a logical vulnerability classified under CWE-384 (Session Fixation / State Confusion) in which OAuth validation cookies could be replayed across different authentication providers.
An unauthenticated remote attacker can trigger the DoS condition by issuing a crafted HTTP request containing an invalid percent-encoded bearer token. This action causes an unhandled runtime error that terminates the request or crashes the application process, depending on the execution environment. The session confusion flaw allows malicious actors to exploit lax cookie validation logic to reuse verification states across different OAuth pathways.
The primary Denial of Service vulnerability originates within the getToken() function, which extracts and processes JSON Web Tokens (JWT) from the client request. When extracting tokens from the Authorization header, the function checks for a Bearer scheme and retrieves the encoded token value. It then passes this value directly to the native JavaScript decodeURIComponent() function.
The native decodeURIComponent() function is highly strict and throws a runtime URIError when encountering malformed percent-encoded characters, such as a trailing % sign, incomplete hex strings like %1, or invalid hex values like %ZZ. Because getToken() executed this parsing routine without wrapping the call in a try...catch block, any thrown URIError bubbled up the call stack. In server environments or server-side edge runtimes, this uncaught exception causes immediate thread termination or returns a HTTP 500 error, disrupting availability.
The secondary vulnerability lies within the OAuth state validation workflow. To defend against Cross-Site Request Forgery (CSRF) and replay attacks, Auth.js stores state, PKCE code verifiers, and nonces in client-side cookies during the authorization phase. Prior to the patch, these verification cookies were generic and lacked an explicit binding to the issuing OAuth provider. Consequently, an attacker could utilize a state cookie generated by Provider A to satisfy the state validation step when initiating an authentication callback via Provider B, causing session and state confusion.
The vulnerability in getToken() is demonstrated by the direct invocation of decodeURIComponent on untrusted user input within packages/next-auth/src/jwt/index.ts and packages/core/src/jwt.ts:
// Vulnerable Code Path
if (!token && authorizationHeader?.split(" ")[0] === "Bearer") {
const urlEncodedToken = authorizationHeader.split(" ")[1]
token = decodeURIComponent(urlEncodedToken) // <-- Throws unhandled URIError
}The corresponding patch introduces robust exception handling to catch parsing errors and return null instead of allowing the application to crash:
// Patched Code Path
if (!token && authorizationHeader?.split(" ")[0] === "Bearer") {
const urlEncodedToken = authorizationHeader.split(" ")[1]
try {
token = decodeURIComponent(urlEncodedToken)
} catch {
// Malformed percent-encoding makes the Bearer token invalid
return null
}
}To resolve the session confusion vulnerability, the OAuth cookie creation and verification logic in packages/next-auth/src/core/lib/oauth/checks.ts was refactored to explicitly bind verification cookies to the provider ID:
// Patched Cookie Signing
export async function signCookie(options) {
return await jwt.encode({
...options.jwt,
maxAge,
token: { value, provider: options.provider.id }, // Bound to provider ID
salt: name,
})
}During callback verification, the code now checks for provider equivalence:
// Patched Verification Check
if (value.provider !== options.provider?.id) {
throw new TypeError(
`The ${name} cookie was created for a different provider than the one handling the callback.`
)
}An attacker can exploit the Denial of Service vulnerability remotely without authentication. The attack vector is a single, malformed HTTP request targeting any application endpoint that performs session checking or invokes middleware.
An operator can simulate and test for the vulnerability using simple utility scripts:
# Test vector 1: Trailing percent character
curl -i -X GET "https://example.com/api/protected" \
-H "Authorization: Bearer %"
# Test vector 2: Malformed hex characters
curl -i -X GET "https://example.com/api/protected" \
-H "Authorization: Bearer %ZZ"
# Test vector 3: Incomplete hex sequence
curl -i -X GET "https://example.com/api/protected" \
-H "Authorization: Bearer %1"If the application is vulnerable, the server returns an HTTP 500 Internal Server Error or drops the connection entirely due to process termination.
The uncaught exception vulnerability significantly degrades availability. Because middleware functions execute early in the request pipeline, a continuous automated stream of malformed headers can easily exhaust server resources, crash Node.js event loops, and prevent legitimate users from accessing any part of the web application.
The session confusion vulnerability impacts the logical integrity of the authentication flow. By replaying valid OAuth verification cookies across different providers, attackers can bypass strict callback constraints or engineer session fixation attacks, potentially leading to unauthorized account linking or privilege escalation.
No official CVE has been assigned to this GHSA entry. However, the estimated severity rating is high, computed as 7.5 under CVSS v3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H). This reflects low attack complexity and the zero-privilege requirement needed to trigger application-wide availability degradation.
The primary resolution is to upgrade all affected packages to their patched versions. If immediate upgrading is not possible, temporary mitigations can be applied at the network perimeter.
Configure Web Application Firewalls (WAF) or reverse proxies to inspect the Authorization header and reject requests that fail URL encoding validation prior to forwarding traffic to the Node.js origin.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
@auth/core Auth.js | < 0.41.3 | 0.41.3 |
next-auth (v4) Auth.js | < 4.24.15 | 4.24.15 |
next-auth (v5) Auth.js | < 5.0.0-beta.32 | 5.0.0-beta.32 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-248 (Uncaught Exception) / CWE-384 (Session Fixation) |
| Attack Vector | Network |
| CVSS v3.1 Score | 7.5 (High) |
| Impact | Availability (High), Integrity (Low) |
| Exploit Status | poc |
| KEV Status | Not Listed |
The software does not handle an exception thrown during critical execution sequences, leading to crashes or server errors.
A security vulnerability in the email normalization logic of NextAuth.js and Auth.js allows remote attackers to bypass email validation constraints and achieve Account Takeover (ATO) through Unicode homoglyph smuggling. Under standard conditions, Unicode compatibility characters represent visually similar symbols that are normalized downstream to ASCII equivalents, facilitating structural validation bypasses. This issue specifically affects passwordless email authentication flows.
CVE-2026-53467 is a heap information disclosure vulnerability in the Multiple-image Network Graphics (MNG) decoder of ImageMagick. The vulnerability arises from a failure to zero-initialize newly allocated pixel cache memory buffers. A remote attacker can exploit this by submitting a crafted sparse MNG image file to trigger uninitialized memory preservation. The resulting output contains residual heap bytes, potentially leaking sensitive process memory or assisting in ASLR bypass.
An untrusted deserialization vulnerability exists in the c3p0 JDBC connection pooling library before version 0.14.0. Standard JDBC getter methods conform to the JavaBean property getter pattern, allowing introspection libraries like Apache Commons BeanUtils to evaluate connection properties dynamically during deserialization, leading to arbitrary code execution when chained with a vulnerable database driver or JNDI sink.
A heap-based buffer overflow vulnerability exists in the native C extension of the Ruby json gem (versions 2.9.0 through 2.19.8) during IO-based streaming serialization. An incorrect buffer size calculation can lead to memory corruption and process termination when processing large strings.
An uncontrolled memory allocation vulnerability (CWE-789) exists in pypdf prior to version 6.14.0. The library blindly trusted user-controlled image dimensions (/Width and /Height) from PDF metadata, allowing attackers to trigger physical memory exhaustion and an Out-of-Memory crash via tiny, malformed files.
An infinite loop vulnerability exists in the pure-python PDF library pypdf prior to version 6.14.1. This vulnerability occurs during the processing of malformed or truncated page content streams containing inline images. Specifically, the parser fails to validate the End-of-Stream condition during inline image dictionary parsing. This results in continuous backward stream-seeking and an infinite loop that consumes 100% CPU on the processing thread.