Jul 23, 2026·6 min read·20 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 path traversal vulnerability (CWE-22) in Contao CMS allows unauthenticated remote attackers to bypass directory boundary restrictions in ImagesController and access files within the project directory.
Contao Open Source CMS versions 4.0.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 contain a Cross-Site Request Forgery (CSRF) vulnerability in backend parameter handling. The `RequestTokenListener` component validates anti-CSRF tokens solely for HTTP POST requests, while GET-based declarative guards run only when an `act` parameter is present in the query string. Consequently, custom backend actions dispatched via alternative parameters such as `key=` can execute without CSRF token verification when triggered by an authenticated user.
Contao CMS versions 4.1.0 through 5.3.49 and 5.4.0-RC1 through 5.7.11 fail to validate form submission tokens and enforce rate limiting when processing activation email resend requests via HTTP POST, enabling resource exhaustion and account state enumeration.
An information disclosure vulnerability in Contao CMS allows unauthenticated site visitors to view protected page titles, URLs, and text excerpts through search queries when protected page indexing is disabled after previously being enabled.
In Vikunja prior to version 2.6.0, relation creation via the CalDAV endpoint fails to invoke the TaskRelation.CanCreate authorization check. This missing access control allows an authenticated user to establish unauthorized relationships and perform write operations against any task, provided its unique identifier (UID) is known.
A cross-project information disclosure vulnerability in Vikunja allows authenticated users with read access to one project to view private task details from unauthorized projects via subtask expansion parameters.