Skip to content

Why Do Some Users See Another Person's Account When They Log In?

7 min read

A user logs in and sees another person's name, data, or dashboard. The most common cause is a personalised page being cached and served to everyone, or a shared server that reuses one user's session for the next request. It is not usually a hack. It is a caching or session bug, and it is fixable. Stop serving traffic until you have found which one it is, because every minute it runs, real accounts are leaking to strangers.

Why this happens

Your AI agent built a page that shows "Welcome back, Sara" and Sara's data. That works perfectly for one user in a demo. The problem shows up only when two people hit your app at once, which never happens while you are building alone.

There are three usual culprits:

  • A CDN or edge cache stored a logged-in page. Vercel, Cloudflare, or a framework's default caching saved the HTML that already had Sara's name baked in, then handed that exact copy to the next visitor. The cache does not know the page was personal.
  • The server reused a session across requests. If the code stashed the current user in a shared variable (a module-level global, a singleton, a cached client) instead of tying it to each request, request two can read request one's user.
  • A token got reused or mixed up. A wrong cache key, a shared API client with one auth header, or a service-role key on the server that fetches "the user" without checking which user.

The agent built exactly what you asked, a page that greets the logged-in user. It did not build the thing you did not ask about: keeping each user's data strictly separate under real concurrent traffic.

How to check

  1. Reproduce it with two browsers. Log in as User A in Chrome and User B in a private window at the same time. Refresh both a few times. If either ever shows the other's name or data, you have confirmed it.
  2. Look for cache headers on your personalised pages. In the browser network tab, click the page request and read the response headers. On a page that shows user data you want to see Cache-Control: private, no-store (or no-cache), and you do not want public, s-maxage, or a CDN HIT status like x-vercel-cache: HIT or cf-cache-status: HIT.
  3. Search your code for shared state. Look for a user, session, or database client stored at module level (outside the request handler) rather than created or looked up per request. On a server that is a red flag.
  4. Check where the current user comes from. Every data query should derive the user from the request's own verified session or token, never from a variable set by a previous request.

The fix

  1. Mark every logged-in page as uncacheable. Add Cache-Control: private, no-store to any response that contains user-specific data. In Next.js, opt personalised routes out of static and full-route caching (mark them dynamic / no-store) so the framework never reuses one user's render for another. Never let a CDN cache a page that shows a name.
  2. Make the current user request-scoped. The user must be resolved fresh inside each request from that request's session or token. Delete any global, singleton, or module-level variable that holds "the current user" or a per-user auth header.
  3. Give every user-data query an owner filter. The query should always say "where this row belongs to the user in this request." On Supabase, turn on Row Level Security so the database itself enforces it. See how to keep one customer's data separate from another's.
  4. Purge the CDN cache after deploying the fix, so the already-poisoned pages are gone.
  5. Re-run the two-browser test and hammer refresh. A leak that only appears under load will not show on a single click.

The trap to avoid

Do not "fix" it by clearing your own cookies, testing once, seeing your own account, and calling it solved. The bug is about two users at once, so a single-user test will almost always look fine while the leak is still live. The other trap is blaming login itself and rebuilding auth. Your login is probably correct. The leak is downstream, in caching or shared server state.

Where this fits

Serving one user's account to another is the single most alarming thing a beta tester can hit, and it is invisible in every solo demo. It is exactly the kind of concurrency and caching gap the free Readiness Report is built to surface, by testing your real app the way two users at once would. If you want the fixes handed to you in order and verified, that is the Finishing Pass. While you are here, it is worth also checking why users stay logged in after logout, which shares the same root causes.