Skip to content

fix(app-router): validate RSC cache-busting params#991

Draft
NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
NathanDrake2406:nathan/issue-988-rsc-cache-busting
Draft

fix(app-router): validate RSC cache-busting params#991
NathanDrake2406 wants to merge 3 commits intocloudflare:mainfrom
NathanDrake2406:nathan/issue-988-rsc-cache-busting

Conversation

@NathanDrake2406
Copy link
Copy Markdown
Contributor

What this changes

Adds a shared App Router RSC cache-busting helper and wires generated RSC entries to reject malformed RSC requests by redirecting them to the canonical _rsc URL. Client-side RSC fetches now send RSC: 1 plus a cache-busting _rsc search param derived from the request headers that can change the RSC payload.

The shared helper also centralizes the App Router RSC Vary header set and includes both Next-compatible headers and Vinext-specific variant headers:

  • RSC
  • Accept
  • Next-Router-State-Tree
  • Next-Router-Prefetch
  • Next-Router-Segment-Prefetch
  • Next-Url
  • X-Vinext-Interception-Context
  • X-Vinext-Mounted-Slots

Fixes #988.

Why

Next.js now treats the URL as the defensive cache key for RSC requests because some CDNs do not respect Vary. The relevant upstream behavior is:

Vinext uses .rsc URLs rather than the exact same visible URL for HTML and RSC, so the HTML-vs-RSC variant is already separated by pathname. The gap is still real because Vinext's .rsc response can vary by request headers such as mounted slots and interception context. A CDN that keys only by URL could serve the wrong RSC payload for another slot or interception context.

Approach

  • Add server/app-rsc-cache-busting.ts as the normal module that owns request headers, _rsc hashing, canonical redirect validation, and the shared RSC Vary value.
  • Keep entries/app-rsc-entry.ts as app-shape codegen: it imports the helper, computes isRscRequest, and delegates validation.
  • Update browser navigation, link prefetch, router prefetch, initial hydration fetches, HMR fetches, and server-action fetches to build canonical RSC request URLs through the helper.
  • Update App Router response helpers to use the shared Vary value.
  • De-duplicate Vary tokens when merging middleware headers, so middleware can add its own Vary values without duplicating the base App Router set.

Validation

  • vp check
  • vp run knip --no-progress
  • vp test run tests/app-rsc-cache-busting.test.ts tests/app-browser-entry.test.ts tests/prefetch-cache.test.ts tests/entry-templates.test.ts
  • vp test run tests/app-rsc-cache-busting.test.ts tests/app-browser-entry.test.ts tests/app-page-cache.test.ts tests/app-page-response.test.ts tests/app-page-boundary-render.test.ts tests/app-page-stream.test.ts tests/app-server-action-execution.test.ts tests/entry-templates.test.ts
  • vp test run tests/app-router.test.ts -t "RSC"

Risks / follow-ups

This intentionally adapts the Next.js invariant to Vinext's current .rsc URL model instead of switching Vinext to same-URL Flight fetches. The hash includes Next-compatible RSC variant headers for forward compatibility and the Vinext-specific headers that currently affect payload shape.

App Router RSC responses could vary by request headers while client fetches and server validation still relied on Vary-aware caches. CDNs that key only by URL could reuse a mounted-slot or interception-context RSC payload for a different request.

Next.js validates a cache-busting _rsc search param against the RSC request headers and redirects malformed requests to the canonical URL. Vinext now applies the same invariant to its .rsc request model, centralizes the RSC Vary header set in normal server modules, and de-duplicates middleware Vary additions.

Tests cover missing and stale _rsc values, variant-header hashes, generated-entry delegation, browser RSC request markers, response Vary propagation, and App Router RSC integration.
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 30, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@991

commit: 535233d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Validate RSC request headers to prevent CDN cache poisoning

1 participant