deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Back-forward cache can resurface authenticated pages after logout, dev.to post warns

A dev.to write-up explains how browser bfcache can reinstate an authenticated page from memory after a user logs out, and which server, header and JavaScript fixes close the gap.

Back-forward cache can resurface authenticated pages after logout, dev.to post warns

The gotcha

Logging out tells the server a session is finished. It does not necessarily tell the browser. A write-up on dev.to draws attention to the back-forward cache, or bfcache, the browser mechanism that holds a fully rendered page in memory so the Back and Forward buttons feel instant. According to MDN, which the post cites, a page brought back from bfcache may never be revalidated against the server. The result is a window in which the session cookie has been destroyed but the last authenticated view is still sitting there, one Back press away.

The scenario the author highlights is the shared machine: someone opens an invoice or account dashboard, signs out, and passes the device to another person. That person hits Back. If the browser serves the page from bfcache, the old DOM appears before the application has any chance to check the session again. Code that only runs during an initial load will not fire, and even a fast client-side redirect can expose the snapshot during the transition.

Header-level mitigation

The most direct instruction to the browser is Cache-Control: no-store. MDN, as referenced in the post, says responses carrying no-store are kept out of bfcache in browsers that support it. The author cautions against applying it indiscriminately: the header also affects ordinary HTTP caching and performance, so it belongs on genuinely sensitive pages rather than every response. The post also flags a common confusion: no-cache is a different directive that still allows storage and merely requires revalidation before reuse. The HTTP cache and bfcache are related but separate systems, and addressing one does not cover the other.

Catching the restore in JavaScript

For pages that must stay bfcache-eligible, the pageshow event offers a hook. It carries a persisted flag that is true when the page has been resurrected from the cache. On that signal, a logout flow can mark local state as signed out, strip sensitive content from the DOM, and request a fresh authorization decision before rendering protected data. The author is explicit that such a handler supplements rather than replaces server-side revocation. Live connections deserve attention too: WebSocket sessions and event streams should be aborted or re-established after restoration, since they can outlive the session they were opened under.

Server and storage hygiene

A complete logout, per the post, revokes the session, clears cookies with the correct attributes, and invalidates refresh tokens or device grants. Where multiple tabs are involved, teams should decide whether logout is global and, if so, broadcast it to other tabs with idempotent handlers. A tab that happened to be offline at the moment of logout should re-verify its session before rendering anything once it becomes active again.

The post also urges an audit of client-side storage. IndexedDB, localStorage, in-memory stores, and service worker caches can all retain sensitive data independently of bfcache. Clearing one surface while leaving others populated reproduces the same disclosure through a different door. The author adds that authorization decisions should never live in client storage where the server cannot verify them, and that each storage surface needs its own retention policy.

Testing the way an attacker would

Finally, the post prescribes a concrete test that matches the threat: sign in as account A, open a sensitive page, sign out, press Back, and record exactly what is visible. Repeat with the network offline after logout, and again after a short delay. Check whether the restored page came from bfcache, whether the server rejects the stale session, and whether cached API responses remain readable, in both the rendered view and the underlying requests.

Why it matters

This is a quiet failure mode: nothing crashes, no error is thrown, and the behavior stems from a browser feature users generally like. That makes it easy to miss in ordinary QA and especially attractive to exploit on shared or borrowed devices. The dev.to post's framing is worth internalizing: treat logout as a coordinated change across the server, the client, and the browser's cache layers, each with its own limits. The practical goal is that a stale snapshot, if the browser shows one at all, contains nothing worth seeing.

  • #web-security
  • #bfcache
  • #session-management
  • #http-headers
  • #browsers