Skip to content

fix: add Next.js RSC headers to CloudFront CachePolicy to prevent cache poisoning#118

Closed
konokenj wants to merge 2 commits intomainfrom
fix/cloudfront-rsc-cache-headers
Closed

fix: add Next.js RSC headers to CloudFront CachePolicy to prevent cache poisoning#118
konokenj wants to merge 2 commits intomainfrom
fix/cloudfront-rsc-cache-headers

Conversation

@konokenj
Copy link
Contributor

Summary

Add Next.js App Router RSC headers (RSC, Next-Router-Prefetch, Next-Router-State-Tree, Next-URL) to the CloudFront CachePolicy CacheHeaderBehavior.allowList to prevent cache poisoning between HTML and RSC flight responses.

Closes #100

Problem

Next.js App Router sends two types of requests to the same URL:

  1. HTML requests — full page loads
  2. RSC requests — client-side navigation with RSC: 1 header

Without these headers in the cache key, CloudFront treats both request types identically. When caching is active (static pages, ISR, or explicit cache headers), an RSC response (text/x-component) can be cached and served for a normal HTML request, or vice versa.

The current sample app uses dynamic rendering (cookies() calls), so Cache-Control: private, no-cache, no-store prevents caching. However, as a starter kit, users will naturally add static pages or ISR, at which point cache poisoning occurs.

Change

 headerBehavior: CacheHeaderBehavior.allowList(
   'authorization',
   'Origin',
   'X-HTTP-Method-Override',
   'X-HTTP-Method',
   'X-Method-Override',
+  'RSC',
+  'Next-Router-Prefetch',
+  'Next-Router-State-Tree',
+  'Next-URL',
 ),

Grounding / References

The fix is validated by multiple independent sources:

  • CVE-2025-49005 (Vercel changelog, GHSA-r2fc-ccr8-96c4): Next.js 15.3.0–15.3.3 had a cache poisoning vulnerability due to missing Vary header. Vercel's recommended workaround for self-hosted deployments: manually set Vary: RSC, Next-Router-State-Tree, Next-Router-Prefetch.
  • Running Next.js behind AWS CloudFront: Documents the exact same issue — RSC responses cached and served as HTML — and recommends adding these headers to CloudFront Cache Policy.
  • cdk-nextjs (jetbridge/cdk-nextjs): Uses rsc, next-router-prefetch, next-router-state-tree, next-url as cache key components (hashed via CloudFront Function into x-open-next-cache-key).
  • CloudFront quota: Cache Policy allows up to 10 headers. Current 5 + 4 added = 9, within the limit.

Verification

  • CDK build passes (npm run build in cdk/)
  • After deployment, HTML requests and RSC requests (RSC: 1 header) to the same URL should produce separate cache entries

…he poisoning

Add RSC, Next-Router-Prefetch, Next-Router-State-Tree, and Next-URL
headers to CacheHeaderBehavior.allowList so that CloudFront
distinguishes RSC flight responses from HTML responses in the cache key.

Without these headers, static/ISR pages can serve text/x-component
data for normal HTML requests (or vice versa) when CloudFront caching
is active.

Closes #100
@konokenj konokenj added this to the v2-fix milestone Mar 20, 2026
@konokenj
Copy link
Contributor Author

Closing in favor of a revised approach using CloudFront Functions to hash RSC headers into a single cache key header, avoiding the 10-header limit on CloudFront Cache Policies.

@konokenj konokenj closed this Mar 20, 2026
@konokenj konokenj deleted the fix/cloudfront-rsc-cache-headers branch March 20, 2026 07:24
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.

CloudFront CachePolicyにNext.js RSCヘッダーが含まれておらずキャッシュ汚染が発生する

1 participant