Full Report
NextJS is a popular ReactJS framework that this website even uses. The function getStaticProps is used for prerendering a page for information already available in the build process. getServerSideProps transmits data at the time of the request based upon the provided data, making it dynamic. The former is cachable while the latter is not. While doing some previous research, they noticed that there are many headers/URL parameters used by NextJs internals. These headers/parameters could be used to change some of the rendering and caching settings. To start with, they found the __nextDataReq=1 parameter would make this a data request. This means that data can be sent back instead of the HTML, using this flag. At first glance, this doesn't matter, but it is a good primitive for cache poisoning. Adding the parameter above to a getServerSideProps call returns the JSON for the page instead. Assuming that URL parameters are not used in caching, this leads to the JSON being returned from the cache instead of the HTML. Diving back into NextJS, they were curious about other ways to control the rendering process. The different routes return different cache-control headers based upon the type of the page. Using the x-now-route-matches can get these headers to change, resulting in unintentional data caching. Crazily enough, the content-type of this page isn't application/json! It's text/html. If any data can be reflected in the page props response, it leads to XSS! The end of the article goes through their bounty payouts. It's interesting that they reported this directly to the owners of NextJS and to many websites with bug bounty programs. To me, this feels weird because the crux of the issue is in NextJS, which paid out. Double dipping seems unfair to the programs. At the same time, if this deep research didn't result in large payouts, then they wouldn't be incentivized to do it. So, is this just the cost of securing the ecosystem or is this morally wrong? I'm not sure. Great research and an awesome article on the internals of caching/NextJS. Followed on Twitter for sure!
Analysis Summary
# Vulnerability: Next.js Internal Header Manipulation & Cache Poisoning
## CVE Details
- **CVE ID:** CVE-2024-46982
- **CVSS Score:** 9.3 (Critical) - *Based on research impact and vendor advisory.*
- **CWE:** CWE-522 (Insufficiently Protected Credentials) / CWE-79 (Cross-site Scripting) / CWE-444 (Inconsistent Interpretation of HTTP Messages)
## Affected Systems
- **Products:** Vercel Next.js
- **Versions:** Versions prior to 14.2.10, 13.5.7, and 12.3.5.
- **Configurations:** Pages utilizing `getServerSideProps` or `getStaticProps` within the Pages Router. Applications deployed on Vercel or using caching proxies (CDNs) that do not normalize internal headers.
## Vulnerability Description
The vulnerability stems from the improper handling of internal Next.js headers, specifically `x-now-route-matches` and the `__nextDataReq` query parameter.
1. **Data Request Manipulation:** By appending `__nextDataReq=1`, an attacker can force Next.js to return raw JSON data (page props) instead of the rendered HTML. If a cache stores this response under the original URL, subsequent users receive truncated JSON instead of the website.
2. **Header Injection:** The `x-now-route-matches` header allows an attacker to override the framework's internal routing logic. This can force a page that should be dynamic (`getServerSideProps`) to adopt the cache-control settings of a static page, leading to **Unintentional Data Caching**.
3. **Content-Type Mismatch (XSS):** Next.js occasionally returns these JSON data props with a `text/html` Content-Type. If any user-controlled input is reflected in the page props (e.g., a username or search query), an attacker can execute **Stored XSS** via the poisoned cache.
## Exploitation
- **Status:** PoC available; widely exploited in bug bounty contexts.
- **Complexity:** Medium
- **Attack Vector:** Network
- **Mechanism:** Cache Poisoning / Cache Deception.
## Impact
- **Confidentiality:** High (Sensitive data in props may be cached and exposed to other users via Cache Deception).
- **Integrity:** High (Stored XSS allows for full account takeover and site defacement).
- **Availability:** High (Denial of Service by poisoning the cache with JSON data instead of HTML).
## Remediation
### Patches
Users should upgrade to the following versions immediately:
- **Next.js 14.2.10**
- **Next.js 13.5.7**
- **Next.js 12.3.5**
### Workarounds
- Configure Web Application Firewalls (WAF) or Reverse Proxies to strip the `x-now-route-matches` header from incoming client requests.
- Ensure CDNs are configured to include all relevant query parameters (like `__nextDataReq`) in the cache key, or block them at the edge.
## Detection
- **Indicators of Compromise:** Unexpected `application/json` or raw JSON structures appearing on URLs that typically serve `text/html`.
- **Detection Methods:** Monitor for requests containing `x-now-route-matches` or `__nextDataReq` originating from external clients. Review cache logs for `HIT` responses on requests with these parameters.
## References
- **Vendor Advisory:** hxxps://github[.]com/vercel/next.js/security/advisories/GHSA-65q6-pcf4-7g6j
- **Original Research:** hxxps://zhero-web-sec[.]github[.]io/research-and-things/nextjs-cache-and-chains-the-stale-elixir
- **PortSwigger Top 10:** hxxps://portswigger[.]net/research/top-10-web-hacking-techniques-of-2025