Skip to content
Go back

[CVE-2025-49005] Cache-poisoning in Next.js App Router swaps HTML for raw React code

Volerion Research

TL;DR
A logic flaw in the App Router’s middleware redirect path lets a React Server Component (RSC) response travel the same route and status code as the surrounding HTML document. Browsers happily cache the first payload they see, so later visitors may receive base64-encoded RSC data instead of a rendered page. Vercel’s managed infrastructure limits the blast radius to each user’s browser cache, but self-hosted deployments that sit behind a generic CDN can poison shared caches project-wide. Upgrade to Next.js 15.3.3 and Vercel CLI 42.2.0, then redeploy.


1. Summary

CVE ID CVE-2025-49005
Affected Product(s) Next.js App Router 15.3.0 through 15.3.2 and Vercel CLI 41.4.1 through 42.2.0
Volerion Risk Score 7.3 / 10
Exploit Status Reproduction steps public
CISA KEV No

The bug allows a malicious or simply unlucky request to prime the cache with an RSC payload. Subsequent visitors see JSON-like gibberish and base64 blobs instead of the fully rendered page. While this is not a direct code-execution issue, it damages availability, can leak snippets of server-side state and opens room for service-mix-up attacks.


2. Context – Why RSC versus HTML matters for caching

React Server Components ship server-side logic to the browser incrementally. They are streamed with the Content-Type: text/x-component header and rely on special request headers (RSC, Next-Router-State-Tree, Next-Router-Prefetch) to differentiate them from normal page requests.

Browsers and CDNs use the full request path and a set of vary headers to decide whether a stored response is reusable. If those headers do not differ between an RSC and an HTML navigation, the first response into the cache wins. The victim sees corrupted markup that the browser cannot parse, effectively converting a modern React site into a blank page.


3. Technical Details

The vulnerable code path sits in the App Router’s handling of middleware-triggered redirects. When a redirect response is generated, the router replays the original request internally. A misplaced condition removed the RSC header during the replay but kept the content-type detection logic unchanged. As a result:

  1. The internal fetch receives the Accept: */* header instead of text/x-component.
  2. Next.js recognises the path as a server component route and streams RSC bytes.
  3. The framework copies status, location and most headers from the first response to the final one, but forgets to update Content-Type, which remains text/x-component.
  4. The response leaves the server with a 200 status, no explicit vary line and the same URL that would normally serve HTML.

Any cache that keys on method + host + path now stores the RSC payload for all clients.

The fix located in commit ec202eccf05820b60c6126d6411fe16766ecc066 adds

+ res.headers.set("Vary", "RSC, Next-Router-State-Tree, Next-Router-Prefetch")

and tightens the type check so that redirected requests never downgrade the header set.


4. Impact

On Vercel’s managed platform the CDN already varies on RSC, so only the browser cache is poisoned. A single user will experience broken navigation until they clear their cache or the item ages out, typically after five minutes.

Self-hosted installs behind Cloudflare, Fastly, Nginx or an AWS ALB often do not distinguish between RSC and HTML out of the box. In those scenarios one malicious request can contaminate edge caches across regions. A marketing campaign or SEO crawler that hits the poisoned URL spreads the bad response to thousands of visitors, causing:

• Loss of availability because pages refuse to render
• Potential disclosure of internal component props, which may include feature flags or user-specific data
• Follow-on attacks such as response-smuggling when intermediaries treat the binary RSC stream as plain text


5. Remediation

Upgrade to:

• Next.js 15.3.3 or later
• Vercel CLI 42.2.0 or later

After upgrading, redeploy the application so the build output includes the patched router logic.

If immediate upgrade is impossible, add a middleware that sets

Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch

on every RSC route. This forces caches to store separate variants for component streams and full HTML pages.


6. Timeline

Date (UTC)Milestone
2025-07-03 21:15CVE-2025-49005 published on GitHub Security Advisories
2025-07-03 21:18Volerion completes enrichment and publishes risk score

7. References


About Volerion

Volerion delivers AI-driven enrichment minutes after a CVE goes live. A single call to our REST API returns CVE metadata, CVSS 3.x and 4.x vectors, exploitability metrics and affected product information complete with remediation guidance. We also calculate the Volerion Risk Score, an aggregate measure that blends eight separate dimensions such as exploit maturity, prevalence and patch effort.

At the time of writing:


Share this post on:

Previous Post
[CVE-2025-54352] WordPress XML-RPC Pingback Leaks Titles of Private and Draft Posts
Next Post
[CVE-2025-34039] Yonyou UFIDA NC BeanShell Servlet Hands Over Remote Code Execution