Skip to content

fix(cache): bypass the backend for requests that arrived with a session - #338

Merged
allen0099 merged 1 commit into
masterfrom
fix/cache-session-bypass
Sep 28, 2026
Merged

allen0099 merged 1 commit into
masterfrom
fix/cache-session-bypass

Conversation

@allen0099

Copy link
Copy Markdown
Owner

Closes #319.

Problem

Since #296, only a request with Authorization bypasses the shared backend. A session token sent as X-Session-Token or as the session cookie did not. So a plain @cache(ttl=...) on a route that reads the session served the first visitor's response to everyone. With AuthenticatedSession, bob got alice's /whoami. With an anonymous session, alice's cart reached bob and a visitor with no cookie at all.

Change

@cache now treats a request as belonging to one caller when any of these holds:

  • it carries Authorization (unchanged);
  • the session middleware loaded a session for it (request.state.__fastapi_cachex_session). This covers all three transports (header, bearer, cookie) and both user and anonymous sessions;
  • request.session is non-empty under any session middleware, Starlette's cookie sessions included.

Such a request takes the existing Authorization path: the backend is neither read nor written, ETag revalidation still runs against the fresh render, and the response goes out with private in place of public. public=True and cache_authorized=True lift the bypass exactly as they do for Authorization. The debug log now names what triggered the bypass.

A token that resolves to no session (forged, expired) does not count. That way, random tokens cannot be used to push traffic past the cache.

Behaviour change: on an app where every browser holds a session (for example a CSRF value in request.session), @cache routes without public=True now answer those requests uncached. That is the safe default, since the handler may read the session. A route whose response does not depend on the session should say so with public=True.

Docs

  • HTTP_CACHING.md and CACHE_FLOW.md describe the session rule next to the Authorization one.
  • HTTP_CACHING.md also warns that authentication with a cookie of the application's own is not detected.
  • SESSION.md gains a note on @cache.
  • The README warning is updated.
  • zh-TW mirrors are updated.
  • Changelog fragment: changelog.d/319.security.md.

Tests

tests/session/test_cache_session_bypass.py has 12 tests. Five of them fail on master:

  • header transport;
  • cookie transport;
  • anonymous cart;
  • the debug log;
  • Starlette session with data.

The other seven guard against over-reaching:

  • bearer;
  • a request with no session is still cached;
  • a bogus header or cookie token is still cached;
  • public=True is shared across sessions;
  • cache_authorized=True with a per-user key caches per user;
  • an empty Starlette session is still cached.

Full suite: 1046 passed, 203 skipped, coverage 93.87%. ruff, mypy strict and pre-commit are clean.

Only Authorization bypassed the shared backend, so a plain @cache on a
route that read the session served the first visitor's response to every
other one: tokens in X-Session-Token or the session cookie, and anonymous
sessions, were not recognised. A request now bypasses the backend and is
answered with private when the session middleware loaded a session for it
or request.session is non-empty; a token that resolves to no session does
not count. public=True and cache_authorized=True lift it as before.

Closes #319
@allen0099 allen0099 added this to the 0.3.9 milestone Sep 28, 2026
@allen0099 allen0099 added bug Something isn't working http-cache The @cache decorator, cache keys and Cache-Control handling session Session management subsystem security Security vulnerability or hardening labels Sep 28, 2026
@allen0099
allen0099 merged commit 376e8a5 into master Sep 28, 2026
12 checks passed
@allen0099
allen0099 deleted the fix/cache-session-bypass branch September 28, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working http-cache The @cache decorator, cache keys and Cache-Control handling security Security vulnerability or hardening session Session management subsystem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@cache: a session token in X-Session-Token or the session cookie does not bypass the shared cache, so users get each other's responses

1 participant