Cache Poisoning in next.js
Description
Next.js is a React framework for building full-stack web applications. By sending a crafted HTTP request, it is possible to poison the cache of a non-dynamic server-side rendered route in the pages router (this does not affect the app router). When this crafted request is sent it could coerce Next.js to cache a route that is meant to not be cached and send a Cache-Control: s-maxage=1, stale-while-revalidate header which some upstream CDNs may cache as well. To be potentially affected all of the following must apply: 1. Next.js between 13.5.1 and 14.2.9, 2. Using pages router, & 3. Using non-dynamic server-side rendered routes e.g. pages/dashboard.tsx not pages/blog/[slug].tsx. This vulnerability was resolved in Next.js v13.5.7, v14.2.10, and later. We recommend upgrading regardless of whether you can reproduce the issue or not. There are no official or recommended workarounds for this issue, we recommend that users patch to a safe version.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
nextnpm | >= 13.5.1, < 13.5.7 | 13.5.7 |
nextnpm | >= 14.0.0, < 14.2.10 | 14.2.10 |
Affected products
1Patches
27ed7f125e07eRemove invalid fallback revalidate value (#69990)
4 files changed · +22 −16
packages/next/src/server/base-server.ts+1 −4 modified@@ -2573,10 +2573,7 @@ export default abstract class Server<ServerOptions extends Options = Options> { return { ...result, - revalidate: - result.revalidate !== undefined - ? result.revalidate - : /* default to minimum revalidate (this should be an invariant) */ 1, + revalidate: result.revalidate, } }, {
packages/next/src/server/render.tsx+1 −0 modified@@ -1089,6 +1089,7 @@ export async function renderToHTMLImpl( }) ) canAccessRes = false + metadata.revalidate = 0 } catch (serverSidePropsError: any) { // remove not found error code to prevent triggering legacy // 404 rendering
test/production/standalone-mode/required-server-files/required-server-files-i18n.test.ts+10 −6 modified@@ -345,12 +345,16 @@ describe('required server files i18n', () => { expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) - const html3 = await renderViaHTTP(appPort, '/some-other-path', undefined, { - headers: { - 'x-matched-path': '/dynamic/[slug]?slug=%5Bslug%5D.json', - 'x-now-route-matches': '1=second&nxtPslug=second', - }, - }) + const html3 = await renderViaHTTP( + appPort, + '/some-other-path?nxtPslug=second', + undefined, + { + headers: { + 'x-matched-path': '/dynamic/[slug]?slug=%5Bslug%5D.json', + }, + } + ) const $3 = cheerio.load(html3) const data3 = JSON.parse($3('#props').text())
test/production/standalone-mode/required-server-files/required-server-files.test.ts+10 −6 modified@@ -622,12 +622,16 @@ describe('required server files', () => { expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) - const html3 = await renderViaHTTP(appPort, '/some-other-path', undefined, { - headers: { - 'x-matched-path': '/dynamic/[slug]', - 'x-now-route-matches': '1=second&nxtPslug=second', - }, - }) + const html3 = await renderViaHTTP( + appPort, + '/some-other-path?nxtPslug=second', + undefined, + { + headers: { + 'x-matched-path': '/dynamic/[slug]', + }, + } + ) const $3 = cheerio.load(html3) const data3 = JSON.parse($3('#props').text())
bd164d53af25Remove invalid fallback revalidate value (#69990)
4 files changed · +22 −16
packages/next/src/server/base-server.ts+1 −4 modified@@ -2385,10 +2385,7 @@ export default abstract class Server<ServerOptions extends Options = Options> { return { ...result, - revalidate: - result.revalidate !== undefined - ? result.revalidate - : /* default to minimum revalidate (this should be an invariant) */ 1, + revalidate: result.revalidate, } }, {
packages/next/src/server/render.tsx+1 −0 modified@@ -1067,6 +1067,7 @@ export async function renderToHTMLImpl( }) ) canAccessRes = false + renderResultMeta.revalidate = 0 } catch (serverSidePropsError: any) { // remove not found error code to prevent triggering legacy // 404 rendering
test/production/standalone-mode/required-server-files/required-server-files-i18n.test.ts+10 −6 modified@@ -344,12 +344,16 @@ describe('required server files i18n', () => { expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) - const html3 = await renderViaHTTP(appPort, '/some-other-path', undefined, { - headers: { - 'x-matched-path': '/dynamic/[slug]?slug=%5Bslug%5D.json', - 'x-now-route-matches': '1=second&nxtPslug=second', - }, - }) + const html3 = await renderViaHTTP( + appPort, + '/some-other-path?nxtPslug=second', + undefined, + { + headers: { + 'x-matched-path': '/dynamic/[slug]?slug=%5Bslug%5D.json', + }, + } + ) const $3 = cheerio.load(html3) const data3 = JSON.parse($3('#props').text())
test/production/standalone-mode/required-server-files/required-server-files.test.ts+10 −6 modified@@ -617,12 +617,16 @@ describe('required server files', () => { expect(isNaN(data2.random)).toBe(false) expect(data2.random).not.toBe(data.random) - const html3 = await renderViaHTTP(appPort, '/some-other-path', undefined, { - headers: { - 'x-matched-path': '/dynamic/[slug]', - 'x-now-route-matches': '1=second&nxtPslug=second', - }, - }) + const html3 = await renderViaHTTP( + appPort, + '/some-other-path?nxtPslug=second', + undefined, + { + headers: { + 'x-matched-path': '/dynamic/[slug]', + }, + } + ) const $3 = cheerio.load(html3) const data3 = JSON.parse($3('#props').text())
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-gp8f-8m3g-qvj9ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-46982ghsaADVISORY
- github.com/vercel/next.js/commit/7ed7f125e07ef0517a331009ed7e32691ba403d3ghsax_refsource_MISCWEB
- github.com/vercel/next.js/commit/bd164d53af259c05f1ab434004bcfdd3837d7cdaghsax_refsource_MISCWEB
- github.com/vercel/next.js/security/advisories/GHSA-gp8f-8m3g-qvj9ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.