Skip to content

Session invalidation is not atomic vs a concurrent token refresh — logout/expiry can be resurrected (no CAS) #212

Description

@heskew

Surfaced during the #211 (logout-invalidation) cross-model review. Verified in code; not yet reproduced — needs a PoC before a fix is designed.

Problem

Session writes are read-modify-write with no optimistic concurrency (no CAS/version check). session.update(...) is a full-replace put on the hdb_session record keyed by id, so last write wins:

  • src/lib/handlers.ts clearOAuthSession persists session.update({ user: null }) (logout / expiry).
  • src/lib/sessionValidator.ts (~L92, ~L169) persists session.update(session) (full write-back of refreshed tokens) on the auto-refresh path.

Race: request A snapshots the authenticated session and awaits token validation/refresh; request B logs the user out and commits { user: null }; A then completes and full-PUTs its stale snapshot (original non-null user + fresh oauth) under the same id. The logged-out session is resurrected and keeps authenticating. (A refresh-vs-refresh variant can also revoke a just-succeeded refresh.)

Scope / severity

Narrow timing window; requires a concurrent in-flight refresh at the logout instant. Pre-existing race class (refresh-vs-refresh already has it); #211's logout fix now participates because logout now (correctly) persists. Hardening-class, not a clean default-exploit.

Direction (to design after reproduction)

Per-session serialization/singleflight on session writes, or optimistic concurrency (version/CAS) on the hdb_session put, or a tombstone that stale writers cannot overwrite. Reproduce first (two concurrent requests, one logout + one refresh) to pin the window.

Priority suggestion: P2.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    Fields

    Priority

    P2

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions