Server Components + Suspense: Rendering User Data to Everyone

Suspense boundaries cache at the layout level by default. When you render personal data inside one, the HTML streams once and serves every viewer.
React Server Components + <Suspense> is the mental model Next.js 15 wants you to adopt. It's also a cache-poisoning vector for vibe-coded apps.
The bug
<Suspense fallback={<Skeleton />}>
<UserGreeting /> {/* reads cookies() → user.name */}
</Suspense>If your page has export const dynamic = "force-static" (intentional or not), Next.js caches the rendered HTML — including <h1>Hello, Alice</h1> — and serves it to the next visitor Bob. Classic stored XSS-of-identity.
Fix
export const dynamic = "force-dynamic"on any route that callscookies(),headers(), orauth()inside server components.- Or move user-specific content to a client component that fetches at render time.
Detect
In production, open an incognito window and a logged-in window side-by-side. The same page should render different <head> (canonical tags may differ) and different user widgets. If incognito shows your logged-in username, you're cached.
VibeWShield's Browser Pass scanner compares two loads of the same URL — authenticated and anonymous — and flags responses whose HTML differs in user-specific tokens when cache headers say they're immutable.
Free security scan
Test your app for these vulnerabilities
VibeWShield automatically scans for everything covered in this article and more — 18 security checks in under 3 minutes.
Scan your app free