- nextjs
- cache
- exploitarium
news
Next.js unstable_cache Object Argument Cache-Key Collision
Passing Request, URLSearchParams, or FormData into unstable_cache() collapses cache keys to {} while callbacks read live per-request data — first writer wins across restarts.
Summary
unstable_cache() on Next.js 16.3.0-canary.70 derives cache keys from JSON.stringify() of object arguments, which serializes Request, URLSearchParams, and FormData to {} even though the cached callback reads cookies, query values, and form fields from the live object. Distinct requests therefore share one Data Cache entry with first-writer semantics, persisting across next start restarts. This proof-of-concept is one of 30 folders in the Exploitarium collection. OFFSITE.DARK summarizes the upstream README and PoC design; we did not discover or weaponize this flaw.
Key Findings
| Finding | Detail |
|---|---|
| Product / target | Next.js 16.3.0-canary.70 (next build + next start) |
| Primitive | Object argument cache-key collision via JSON.stringify → {} |
| Impact | Cross-user cache bleed for routes that pass request wrapper objects into unstable_cache() instead of extracted primitives. |
Attack Chain
alice request → unstable_cache(Request) stores alice cookie → bob request same cache group → returns alice values → restart next start → charlie still sees alice
Mitigation
Never pass Request, URLSearchParams, or FormData objects as unstable_cache arguments; extract primitive cache-key components first; audit Data Cache usage on multi-tenant routes.