Jul 24, 2026·7 min read·4 visits
Auth.js and NextAuth.js fail to bind anti-CSRF cookies to specific OAuth identity providers, allowing attackers to replay session parameters across provider callback boundaries and dynamically link unauthorized identity accounts.
A critical logical security flaw exists in Auth.js (formerly NextAuth.js) where signed anti-CSRF check cookies (state, nonce, and PKCE code_verifier) are not bound to the specific Identity Provider that initiated the authorization flow. In multi-provider environments, this allows an attacker to replay valid, cryptographically signed cookies minted during a flow with one provider against a callback handling a different provider. This vulnerability can lead to session hijacking, identity theft, or unauthorized account linking.
This report analyzes a logical security flaw in Auth.js (formerly NextAuth.js), an open-source authentication library for Node.js environments. The vulnerability, tracked under GHSA-X445-F3H2-J279, belongs to the class of OAuth Provider Confusion (also known as OAuth Mix-up) issues. This flaw manifests in multi-provider configurations where more than one identity provider is registered concurrently.
The attack surface involves the endpoints handling the callback responses from external Identity Providers (IdPs). To maintain session and flow integrity across stateless HTTP redirects, the library relies on cryptographically signed cookies containing state parameters, cryptographic nonces, and Proof Key for Code Exchange (PKCE) verifiers.
Prior to remediation, Auth.js did not bind the generated security parameters to the specific Identity Provider that initiated the flow. This allowed valid, cryptographically sound security tokens minted for a low-trust or attacker-controlled provider to be replayed and successfully validated during callback processing for a high-trust provider.
The root cause of this vulnerability lies in the logical decoupling of anti-CSRF and flow-state parameters from the structural context of their originating Identity Provider. When an authorization sequence begins, Auth.js generates key security parameters to maintain flow security. These parameters include the state (to prevent CSRF), the nonce (to prevent ID token replay), and the code_verifier (for PKCE flow integrity).
To prevent client-side manipulation, the application signs or encrypts these parameters using the JSON Web Encryption (JWE) or JSON Web Token (JWT) standards, keyed by the global NEXTAUTH_SECRET environment variable. The resulting encrypted payloads are set as client-side cookies under generic names such as next-auth.state or next-auth.pkce.code_verifier. These cookie names are shared globally across all authentication providers configured within the application runtime.
During callback handling, the backend routing architecture retrieves these encrypted cookies, decrypts them using the global secret, and validates that their internal values match the incoming parameters provided by the redirect query. The validation routine did not evaluate whether the active cookie had been generated for the specific Identity Provider currently processing the callback. The application only verified the cryptographic integrity and expiration of the parameter itself, leading to a session security gap.
The vulnerability's code-level manifestation and subsequent remediation can be analyzed in both the NextAuth.js v4 branch and the Auth.js v5 (@auth/core) branch. In both instances, the fix introduces a provider binding mechanism into the signed cookie payload.
In the vulnerable v4 implementation inside oauth/checks.ts, the cookie signing process was implemented as follows:
// VULNERABLE: next-auth v4 (oauth/checks.ts)
export async function signCookie(
options: Record<string, any>,
name: string,
value: string,
maxAge: number
) {
return await jwt.encode({
...options.jwt,
maxAge,
token: { value }, // Only the parameter value is encapsulated
salt: name,
})
}The corresponding validation logic did not inspect provider context, allowing any validly signed cookie to pass check validation. The patch introduced in commit 5bca2399a79ba8d116ca5179b4b1ebcd152e7f05 altered both the creation and verification phases:
// PATCHED: next-auth v4 (oauth/checks.ts)
export async function signCookie(
options: Record<string, any>,
name: string,
value: string,
maxAge: number
) {
return await jwt.encode({
...options.jwt,
maxAge,
// The active provider's unique ID is now bound to the token payload
token: { value, provider: options.provider.id },
salt: name,
})
}During consumption, the validation handlers (such as PKCE, State, and Nonce managers) now strictly enforce that the provider ID stored in the decrypted cookie matches the provider executing the callback handler. This is demonstrated in the patched PKCE check:
// PATCHED: next-auth v4 PKCE verification (oauth/checks.ts)
if (!value?.value)
throw new TypeError("PKCE code_verifier value could not be parsed.")
// Strict check to block cross-provider token replay
if (value.provider !== options.provider?.id) {
throw new TypeError(
`${name} cookie was created for a different provider than the one handling the callback.`
)
}In the Auth.js v5 core branch, the fix was implemented in commit 9f7a97fade9b1319bb9ac19fc9828d62e0a2a852 by updating checks.ts. The updated logic enforces the same provider equality matching in the parseCookie utility:
// PATCHED: @auth/core v5 cookie validation (checks.ts)
async function parseCookie(
// ... parameters ...
) {
if (!parsed?.value) throw new Error("Invalid cookie")
// Enforce that the cookie provider ID equals the active callback provider ID
if (parsed.provider !== options.provider?.id) {
throw new Error(
`${name} cookie was created for a different provider than the one handling the callback`
)
}
return parsed.value
}Exploiting GHSA-X445-F3H2-J279 requires an application configuration where at least two OAuth/OIDC providers are configured, and where account linking is either enabled or automatically performed based on user attributes. The attacker must also have a valid account on a low-trust or attacker-controlled identity provider configured within the target system.
The attack sequence proceeds as follows. First, the attacker initiates a legitimate login sequence on the target application utilizing their own low-trust provider credentials. The application generates and sets cryptographically signed security parameter cookies (state, nonce, code verifier) on the attacker's client browser.
Second, the attacker intercepts these state cookies or crafts a social-engineering link. This link is designed to force the victim's browser to execute the callback sequence for a high-trust identity provider (such as a corporate OIDC tenant), but using the security parameter tokens corresponding to the session initiated with the attacker's low-trust provider.
Third, because the target application decrypts the incoming cookies and validates them against the current session data, the signature check succeeds. The application's backend server has no logical record that the cookies were meant for the low-trust flow rather than the high-trust flow. It therefore accepts the authorization code returned by the high-trust IdP, leading to successful authentication or automatic account linking. This effectively binds the attacker's identity provider credentials to the victim's profile, granting the attacker permanent unauthorized access.
The security impact of GHSA-X445-F3H2-J279 is significant, particularly in enterprise or multi-tenant deployments that aggregate multiple identity sources. By manipulating the provider selection during the OAuth authorization flow, an attacker can bypass standard security assumptions associated with high-trust directory services.
The primary consequence of this vulnerability is arbitrary account linking. If an application is configured to automatically link accounts sharing matching email addresses or profiles, an attacker can associate their low-trust identity credentials with an elevated-privilege corporate user account. Once linked, the attacker can authenticate using their low-trust account to access the victim's session resources and administrative controls.
This logical validation bypass has been categorized with a CVSS v3.1 score of 7.5 (High) due to the low complexity of exploitation and the potential for complete compromise of user accounts. It bypasses both the cross-site request forgery protections (CWE-352) and session fixation protections (CWE-384) built into modern OAuth client architectures.
Remediation of the vulnerability requires upgrading the core library dependencies immediately. The fix is backported and available across all major active release channels of the ecosystem.
For teams maintaining NextAuth.js v4 applications, upgrade the dependency to next-auth@4.24.15 or newer. For teams utilizing the Auth.js v5 beta architecture, upgrade to next-auth@5.0.0-beta.32 or newer. Projects consuming the core decoupled core logic should update to @auth/core@0.41.3.
# Upgrade commands for different project configurations
npm install next-auth@4.24.15
npm install next-auth@5.0.0-beta.32
npm install @auth/core@0.41.3> [!IMPORTANT] > Because legacy cookies issued prior to the patch lack the provider property inside their sealed JSON payloads, updating the server-side code will invalidate all active in-flight authentication flows. Users midway through an OAuth redirect during deployment will experience a validation error and must restart their login sequence.
In addition to updating dependencies, teams should audit their multi-provider dynamic registration logic. Ensure that no custom OAuth providers are defined with overlapping, generic, or duplicate ID string properties, as matching provider IDs would still evaluate as equal during validation checks, undermining the security patch.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
next-auth Auth.js | < 4.24.15 | 4.24.15 |
next-auth (v5) Auth.js | < 5.0.0-beta.32 | 5.0.0-beta.32 |
@auth/core Auth.js | < 0.41.3 | 0.41.3 |
| Attribute | Detail |
|---|---|
| Vulnerability ID | GHSA-X445-F3H2-J279 |
| Weakness Class | CWE-384 (Session Fixation) / CWE-352 (CSRF) |
| CVSS v3.1 Score | 7.5 (High) |
| Attack Vector | Network / Remote |
| User Interaction | Required (Targeted redirect execution) |
| Exploit Status | PoC (Verified in test suite) |
| Patched Versions | next-auth >= 4.24.15, next-auth >= 5.0.0-beta.32, @auth/core >= 0.41.3 |
The software reuse of an established session identifier or security parameters allows unauthorized clients to hijack session flows or bypass flow checks.
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.
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.
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.