CVE-2024-46982
Executive Summary
CVE-2024-46982 is a cache poisoning vulnerability in Next.js, a popular React framework. By sending a crafted HTTP request, an attacker can force a non-dynamic server-side rendered (SSR) route in the Pages Router to be cached, even though it is intended to be dynamic. This can lead to stale or malicious content being served to users, and upstream CDNs may also cache the poisoned response due to a Cache-Control: s-maxage=1, stale-while-revalidate header. The vulnerability affects Next.js versions 13.5.1 through 14.2.9 when using the Pages Router with non-dynamic SSR routes (e.g., pages/dashboard.tsx). The App Router is not affected. The issue was patched in versions 13.5.7 and 14.2.10.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Next.js is distributed via the npm registry. Organizations using Next.js should immediately audit their package.json for affected versions and update to the patched releases. Since this is a framework-level vulnerability, any application using the affected versions is at risk. There are no known malicious packages exploiting this CVE, but the attack vector is straightforward and could be weaponized in automated scans.
CVSS Breakdown & Threat Level
- CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
- Base Score: 7.5 (High)
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: None (PR:N)
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: None (C:N)
- Integrity Impact: High (I:H)
- Availability Impact: None (A:N)
The high integrity impact reflects the ability to serve poisoned content to all users, potentially including malicious scripts or outdated data. The low attack complexity and no required privileges make this a serious threat for unpatched deployments.
Deep Dive & Mechanics
The vulnerability lies in how Next.js handles cache-control headers for non-dynamic SSR routes in the Pages Router. When a request is made to a route like /dashboard, Next.js normally generates the page on each request (SSR). However, by sending a crafted HTTP request with specific headers (e.g., x-vercel-id or other internal headers), an attacker can trick the framework into treating the response as cacheable. The server then responds with a Cache-Control: s-maxage=1, stale-while-revalidate header, which tells CDNs and browsers to cache the response for a short time. This allows the attacker to poison the cache with a response that may contain manipulated data.
The root cause is that Next.js does not properly validate whether a route is intended to be dynamic before applying caching headers. The fix in patched versions ensures that non-dynamic SSR routes always receive a Cache-Control: no-cache, no-store, must-revalidate header, preventing any caching.
Vulnerable vs. Patched Code
Vulnerable Code (Next.js < 13.5.7 / < 14.2.10): In the Pages Router rendering pipeline, the cache-control header is set based on the route type. For non-dynamic SSR routes, the header is incorrectly set to allow caching when certain request conditions are met.
// Simplified vulnerable logic
if (isSSRRoute && !isDynamicRoute) {
// Missing check for cache poisoning
response.setHeader('Cache-Control', 's-maxage=1, stale-while-revalidate');
}
Patched Code (Next.js >= 13.5.7 / >= 14.2.10): The fix adds a check to ensure that non-dynamic SSR routes are never cached.
// Patched logic
if (isSSRRoute && !isDynamicRoute) {
// Force no caching
response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
}
The patch also includes validation of incoming request headers to prevent cache poisoning attempts.
Exploitation & Lab Setup
Red Team (Exploitation)
To exploit CVE-2024-46982, an attacker sends a crafted HTTP request to a vulnerable Next.js application. The request must target a non-dynamic SSR route (e.g., /dashboard) and include specific headers that trigger the cache poisoning. Below is a proof-of-concept using curl.
# Exploit PoC for CVE-2024-46982
# Replace target.com with the vulnerable application
curl -X GET "https://target.com/dashboard" \
-H "Host: target.com" \
-H "x-vercel-id: cache-poison" \
-H "User-Agent: Mozilla/5.0" \
-H "Accept: text/html"
The response will include a Cache-Control: s-maxage=1, stale-while-revalidate header. Subsequent requests from other users may receive the cached (poisoned) response.
Lab Setup:
- Deploy a Next.js application with version 14.2.9 using the Pages Router.
- Create a non-dynamic SSR route:
pages/dashboard.tsx. - Run the application with
next start. - Send the crafted request and observe the cache header.
Blue Team (Detection & Hardening)
Detection:
- Monitor for requests containing unusual headers like
x-vercel-idorx-nextjs-cachetargeting SSR routes. - Look for responses with
Cache-Control: s-maxage=1, stale-while-revalidateon non-dynamic pages. - Use WAF rules to block requests with suspicious cache-related headers.
Hardening:
- Immediately upgrade to Next.js v13.5.7 or v14.2.10.
- If upgrade is not possible, implement a reverse proxy (e.g., Nginx) to strip or override cache headers for SSR routes.
- Disable caching at the CDN level for paths that should not be cached.
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests with header
x-vercel-id: cache-poisonor similar variations. - HTTP responses with
Cache-Control: s-maxage=1, stale-while-revalidateon non-dynamic SSR routes.
- HTTP requests with header
- File IOCs:
- Modified
package.jsonshowing Next.js version between 13.5.1 and 14.2.9.
- Modified
- Behavioral IOCs:
- Unexpected caching of pages that are normally dynamic.
- Users receiving stale or manipulated content.
Detection Engineering
YARA Rule
rule CVE_2024_46982_NextJS_CachePoison {
meta:
description = "Detects cache poisoning attempts against Next.js CVE-2024-46982"
author = "Valters IT"
date = "2024-10-27"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2024-46982"
strings:
$header1 = "x-vercel-id" nocase
$header2 = "x-nextjs-cache" nocase
$cache_control = "s-maxage=1, stale-while-revalidate" nocase
condition:
any of ($header*) and $cache_control
}
Sigma Rule
title: Next.js Cache Poisoning Attempt (CVE-2024-46982)
id: 8a3f7c2e-9b1d-4e5f-8c7a-6d2b1e3f4a5c
status: experimental
description: Detects HTTP requests with suspicious headers targeting Next.js SSR routes
author: Valters IT
date: 2024-10-27
logsource:
category: webserver
product: nextjs
detection:
selection:
cs-method: 'GET'
cs-uri-stem|contains:
- '/dashboard'
- '/profile'
- '/settings'
cs-headers|contains:
- 'x-vercel-id'
- 'x-nextjs-cache'
condition: selection
falsepositives:
- Legitimate CDN requests
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2024-46982 Next.js Cache Poisoning Attempt"; flow:to_server; content:"GET"; http_method; content:"x-vercel-id"; http_header; content:"x-nextjs-cache"; http_header; sid:1000001; rev:1;)
Remediation & Mitigation
- Immediate Patch: Upgrade Next.js to v13.5.7 or v14.2.10 (or later). Run
npm update nextoryarn upgrade next. - Workaround: If patching is not possible, configure a reverse proxy (e.g., Nginx) to override
Cache-Controlheaders for SSR routes:location /dashboard { proxy_pass http://nextjs_app; proxy_hide_header Cache-Control; add_header Cache-Control "no-cache, no-store, must-revalidate"; } - CDN Configuration: Ensure CDN rules do not cache responses with
s-maxage=1for SSR paths. - Monitoring: Enable logging of all HTTP headers and monitor for anomalous cache-related headers.
Valters IT - DevSecOps & Cyber Threat Intelligence