Imagine loading a web page and seeing someone else’s username. Strange, right? You’re not hacking anything, you’re just casually browsing. That’s basically what happened when a caching hiccup at Vercel made SSR (Server Side Rendered) pages spill over user data to others. Yikes! Let’s break down what happened, why it was bad, and how a savvy fix saved the day.
TL;DR (Too Long, Didn’t Read)
Vercel’s Edge Caching system mistakenly shared cached SSR pages across different users. This led to user session data being leaked between visitors. The underlying problem? Cache keys didn’t account for request headers that separate one user from another. The fix was smart: match the right headers to ensure isolated and private responses.
Why SSR is Awesome (and Risky)
SSR stands for Server Side Rendering. It means the server builds a complete web page for you before it reaches your browser. This makes things super fast and SEO-friendly. But there’s a trade-off: every page served must reflect the specific user’s session and data.
Now imagine if the data shown wasn’t your data. That’s what can happen if the cache gets involved and forgets who asked for what.
Enter Vercel and Edge Caching
Vercel is a popular platform for hosting static and dynamic websites. It uses Edge Caching to make SSR pages even faster, by storing pre-built pages closer to users around the world. The closer the content, the quicker the load. Sounds great, right?
But the problem is, caching dynamic content is tricky.
Image not found in postmeta
What Went Wrong
When a user requested an SSR page, Vercel’s edge servers decided to store the response—temporarily. Then they reused it for the next visitor to save time. Perfect for performance, terrible for privacy.
Here’s the core of the problem: The caching system didn’t check important request headers like cookies or authorization tokens when making the cache key. So, if Alice logged in and loaded a page, her personalized version of the page might be cached. Then Bob visited that same page—and saw Alice’s data!
Oops.
The root issue was that the cache key—used to identify what’s stored—was too generic. It didn’t account for the user-specific details carried in headers.
How Dangerous Was It?
Very. Here’s why:
- Logged-in users could see each other’s info.
- Admin-only pages might appear for regular users.
- Session leaks could mess up user flows or show inappropriate content.
Basically, the fundamental rule of the web—each user sees their own view—was broken.
How It Was Discovered
Developers started noticing weird behavior. Test users were seeing data they shouldn’t. Logs didn’t match what the browser showed. Something was fishy.
The common pattern? All were using SSR routes hosted on Vercel, and many were seeing sessions bleed between users. At first, it was hard to pin down. But soon, eyes turned to edge caching.
Diving Deeper Into Headers
In web requests, headers are like little notes that travel from browser to server. They say things like:
- Cookie: stores user sessions
- Authorization: holds tokens for logged-in status
- Accept-Language: user preferences
If the cache doesn’t consider these, it might serve the same response to very different users.
The Heroic Fix: Header-Based Cache Matching
Developers and Vercel engineers realized that they needed smarter caching. The solution was elegant: header matching.
With header matching, the cache key includes all—or specific—headers that affect the content of the response. That way, a login cookie triggers a separate entry in the cache, isolating user sessions.
Image not found in postmeta
How It Works Now
When someone requests a page:
- The edge server looks at the request headers.
- It creates a unique cache key based on chosen headers (like Cookie, Authorization).
- If there’s no match, it runs the SSR rendering logic and stores that version keyed to those headers.
- Future requests from others get their own key based on their headers.
Choosing the Right Headers
Matching all headers can be expensive. Not every header affects the output. So developers can now:
- Pick specific headers to include in caching logic
- Set up rules to vary content by user type or role
- Ensure that personalized content never leaks
Takeaways for Developers
If you’re building dynamic web apps, this story is a good reminder:
- Caching is powerful—but needs care
- Always think about the context (user, device, region)
- Use header-based cache variation when personalization is involved
It’s also good to test caching behavior thoroughly. Try logging in as one user, then another. Spot check behavior.
How to Use Header Matching in Vercel
Vercel now offers tools to define which headers your cache should consider. It’s easy to set up in your vercel.json config file or within the framework you’re using (like Next.js).
Example:
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Cache-Control",
"value": "public, s-maxage=60, stale-while-revalidate=30"
},
{
"key": "Vary",
"value": "Cookie, Authorization"
}
]
}
]
}
Here, the Vary header tells Vercel to treat responses differently depending on those headers. Super useful!
Real-World Impact
Many apps fixed the issue quickly once they knew. But there were potential exposures before the issue was understood. Some users might have seen data they shouldn’t. Thankfully, the change to header-aware caching stopped the hemorrhage.
Image not found in postmeta
Final Thoughts
Caching is one of the biggest ways to make web apps fast. But if you don’t get it exactly right, it can go very wrong.
Vercel’s edge caching system now includes a smarter, more secure way of handling server-rendered pages. When used correctly, it keeps things fast and respects user privacy. A win-win!
So next time you deploy an SSR app, ask yourself: “What headers might affect this content?” Pin that down, and you’ll cache like a pro.
logo

