When a Cache Shows One Customer Someone Else's Data

A cache is meant to speed things up, not mix up your customers. Here's how personalised data ends up served to the wrong person, and what to check before it happens to you.

A client of mine once had a support ticket that made no sense. A customer logged into their portal and saw someone else's name in the top corner, for about a second, before it corrected itself. No hack, no breach, nobody's password had been guessed. It was a cache doing exactly what it had been told to do, and nobody had told it the page was personal.

This kind of thing is more common than most business owners realise, and it rarely gets caught until a customer notices and complains.

What a cache is actually doing

A cache sits between your app and the person using it, and stores a copy of a response so the next request doesn't have to be built from scratch. It might live in a browser, a content delivery network in front of your site, or a reverse proxy on your own server. The point of all of them is the same: don't do the same work twice if you don't have to.

That's fine when the response is the same for everyone, like a product page or a blog post. It stops being fine the moment the response is different depending on who's asking, like an account page, a dashboard, or an invoice.

Where it goes wrong

The technical name for the fix is the Vary header, a small instruction that tells a cache "this response depends on something specific about the request, so don't hand out the same copy to everyone." Without it, a cache has no way of knowing that the page it just stored for one customer contains that customer's name, order history or account balance.

So it does what caches do. It serves that stored copy to the next person who asks for the same URL, cookies or not. If two customers are on the same corporate network, or one refreshes just after another, the timing can line up badly enough that one briefly sees the other's data.

This isn't a rare edge case in complicated systems. It's a natural side effect of adding speed improvements over time. A site starts simple, gets a CDN in front of it for performance, someone adds a caching layer to an API to cut costs, and none of that gets revisited when a new personalised feature is added six months later. Nobody set out to leak anything. The caching layer just doesn't know the rules changed.

Why this matters more than it sounds

The obvious risk is a customer seeing something they shouldn't, which is a data protection problem the moment it involves anyone's name, order or financial detail. But there's a second-order risk too: once it's happened once, it can happen again in a slightly different place, because the underlying cause is usually structural rather than a one-off bug. If one endpoint was caching personalised responses without saying so, others probably are too.

It also tends to surface at the worst possible moment, under load, when caching is doing the most work and the most requests are overlapping. That's often right when a business can least afford a support disaster, during a launch, a sale, or a busy period.

I've written before about how data can leak without a system ever being hacked, and this is the same idea from a different angle. Nobody broke in. The software just did something it wasn't meant to.

What to actually check

You don't need to understand the internals to ask the right questions of whoever built or maintains your system:

  • Which pages or API responses are different depending on who's logged in?
  • Is anything in front of the app (a CDN, a proxy, a hosting platform's built-in cache) storing full page responses rather than just static assets?
  • Are personalised responses explicitly marked as not cacheable, or cacheable only per user?
  • Has anyone tested what happens when two different logged-in users hit the same URL close together?

That last one is the practical test. It's easy to check locally, it takes a few minutes, and it's the sort of thing that gets skipped because it doesn't show up in normal testing, where one person is usually clicking around on their own.

Where this fits with the rest of the build

Caching is a performance decision, and performance decisions have to be made with an eye on what's actually personal in your system, not just what's slow. It's one of those details that's cheap to get right early and expensive to untangle later, once a CDN configuration or a third-party integration has quietly baked in the wrong assumption.

If you're not sure whether your own portal or app treats personalised pages differently to public ones, it's worth asking whoever built it directly rather than assuming it's been thought through. It's a five minute conversation now, or a difficult one later when a customer emails asking why they saw someone else's invoice.