The vulnerability exists because Next.js applications using the App Router and Content Security Policy (CSP) with nonces were susceptible to a stored cross-site scripting (XSS) attack. The root cause was twofold:
-
Improper Nonce Validation: The function getScriptNonceFromHeader in packages/next/src/server/app-render/get-script-nonce-from-header.tsx failed to properly validate and sanitize the nonce value extracted from the Content-Security-Policy HTTP request header. It used a weak method to parse the nonce, allowing malformed and malicious strings (e.g., containing HTML characters like " or >) to be accepted as valid nonces.
-
Lack of Output Escaping: The nonce value, once extracted, was insecurely embedded directly into script tags in the HTML response by functions like createServerInsertedMetadata and createInlinedDataReadableStream. These functions did not perform the necessary HTML attribute escaping on the nonce value.
An attacker could exploit this by sending a request with a crafted Content-Security-Policy header containing a malicious nonce. If the response was stored in a shared cache, subsequent users accessing that cached page would have their browsers execute the malicious script embedded in the response. The patch addresses this by implementing strict validation of the nonce format using a regular expression and ensuring that the nonce is always properly escaped using a new htmlEscapeAttributeString function before being included in the HTML.