Session resumption after network interrupt requires re-auth
Why it matters
Storing session tokens in localStorage means they survive browser restart, tab close, and OS sleep. An attacker with brief physical access, an XSS payload, or a malicious browser extension can exfiltrate a localStorage token and replay it from any machine at any time — the user's network disconnect or tab close provides no protection. CWE-384 (Session Fixation) and CWE-287 (Improper Authentication) both apply when a stale persistent token is accepted as proof of identity. NIST 800-63B IA-11 specifically addresses re-authentication requirements after session interruption. Financial applications that auto-resume from disk-persisted tokens effectively eliminate the security benefit of inactivity timeouts.
Severity rationale
Medium because the attack requires the token to be exfiltrated first (via XSS, physical access, or extension), but once captured, a localStorage-persisted token grants indefinite session resumption without any re-authentication barrier.
Remediation
Switch to sessionStorage (cleared on tab close) and never write session tokens to localStorage. Enforce this in src/lib/auth.ts:
// sessionStorage clears on tab close — correct for financial sessions
sessionStorage.setItem('sessionToken', token);
// Guard all protected routes against absent in-memory sessions
if (!sessionStorage.getItem('sessionToken')) {
redirect('/login'); // require fresh authentication
}
// Never write session tokens to localStorage
// localStorage.setItem('sessionToken', token); // XSS-exfiltrable, persists after browser restart
For token refresh flows, only issue a new token while an in-session sessionStorage entry is present — do not issue tokens on cold starts from stored data.
Detection
- ID:
resumption-requires-reauth - Severity:
medium - What to look for: Count all session persistence mechanisms (localStorage, sessionStorage, persistent cookies, IndexedDB) and enumerate which ones store authentication tokens. Quote the actual storage API calls found. Verify that no mechanism allows automatic session resumption across browser restarts without re-authentication. A localStorage-based token that survives browser restart does not count as pass.
- Pass criteria: After network interrupt or tab closure, at least 1 re-authentication step is required before accessing protected resources. Count all token storage locations — 0 must use localStorage for session tokens. Report the count even on pass (e.g., "0 localStorage token stores, session uses sessionStorage only, re-auth required on tab reopen").
- Fail criteria: Session automatically resumes from stored data without re-authentication, or any session token is stored in localStorage (persists across browser restarts).
- Skip (N/A) when: The application has no network-dependent features or is fully offline-capable by design — cite the actual architecture found.
- Detail on fail:
"Session token in localStorage — auto-resumes across browser restarts, 0 re-auth required. 1 of 1 token stores uses localStorage." - Remediation: Restrict session resumption to within-session only (in
src/lib/auth.ts). Use sessionStorage (not localStorage) and do not persist session tokens to disk:// Use sessionStorage (cleared on tab close) not localStorage sessionStorage.setItem('sessionToken', token); // Never store sensitive tokens in localStorage // Implement token refresh only for in-session recovery, not cross-session if (!sessionStorage.getItem('sessionToken')) { // No in-memory session available — require login redirect('/login'); }
External references
- cwe · CWE-384 — Session Fixation
- cwe · CWE-287 — Improper Authentication
- owasp:2021 · A07
- nist:rev5 · IA-11 — Re-Authentication
Taxons
History
- 2026-04-18·v1.0.0·Initial import from finserv-session-security·automated