# Session data not in localStorage; memory-only or secure cookie

- **Pattern:** `ab-001476` (`finserv-session-security.session-integrity.session-data-not-local-storage`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001476
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001476)

## Why it matters

localStorage persists across browser restarts, operating system sleeps, and shared-device sessions. Any XSS vulnerability on any page of the application — including third-party scripts loaded on marketing pages — can read `localStorage` across the entire origin and exfiltrate every stored token. CWE-922 (Insecure Storage of Sensitive Information) and CWE-312 (Cleartext Storage of Sensitive Information) both apply. OWASP A02 (Cryptographic Failures) addresses insecure data at rest. PCI-DSS Req 6.4.1 forbids storing sensitive authentication data where scripts can access it. In a financial application, a single-line `localStorage.getItem('authToken')` in an XSS payload yields a portable, replayable session credential.

## Severity rationale

Low because the attacker requires a co-located XSS vulnerability to exploit localStorage exposure, but when that condition is met, every session token stored there is immediately and silently exfiltrable to an external server.

## Remediation

Eliminate all `localStorage.setItem` calls that store authentication or session data. Use React Context for in-memory state and rely on server-set HTTP-only cookies for the session token. In `src/context/AuthContext.tsx`:

```js
const AuthContext = createContext<{ user: User | null }>({
  user: null
});

export function AuthProvider({ children }: { children: React.ReactNode }) {
  // User state lives only in memory — cleared on page refresh
  const [user, setUser] = useState<User | null>(null);
  return (
    <AuthContext.Provider value={{ user }}>
      {children}
    </AuthContext.Provider>
  );
}
// Never: localStorage.setItem('authToken', token);
// Never: sessionStorage.setItem('authData', JSON.stringify(user));
```

Grep the codebase for `localStorage.setItem` and `sessionStorage.setItem` — any hit containing `token`, `auth`, `session`, `user`, or `jwt` in the key name is a finding that must be removed.

## Detection

- **ID:** `session-data-not-local-storage`
- **Severity:** `low`
- **What to look for:** Count all localStorage.setItem and sessionStorage.setItem calls that store auth/session data. Quote the actual storage key names found (e.g., 'token', 'sessionToken', 'authData'). Enumerate the secure alternatives used (HTTP-only cookies, React state, Context). Any session token in localStorage must not pass — do not pass if any sensitive token is stored in localStorage.
- **Pass criteria:** Session tokens stored only in memory (React state, Context) or secure HTTP-only cookies. Count all localStorage/sessionStorage calls — 0 must store sensitive session tokens. Report the count even on pass (e.g., "0 localStorage session stores, auth data in React Context + HTTP-only cookie").
- **Fail criteria:** Any session token or sensitive data in localStorage (even 1 instance), or sessionStorage used for persistent auth tokens.
- **Skip (N/A) when:** The application is a static site with no session management — cite the actual architecture found.
- **Detail on fail:** `"1 localStorage.setItem('authToken', ...) found in src/lib/auth.ts:23 — session token exposed to XSS"`
- **Remediation:** Store session data securely (in `src/lib/auth.ts` or `src/context/AuthContext.tsx`):
  ```js
  // DON'T DO THIS:
  // localStorage.setItem('sessionToken', token);
  // sessionStorage.setItem('authData', JSON.stringify(user));

  // DO THIS instead:
  // Use HTTP-only cookies (set by server)
  // Or use memory with Context API

  // lib/auth.ts (React Context example)
  const AuthContext = createContext<{ user: User | null }>({ user: null });

  export function AuthProvider({ children }) {
    const [user, setUser] = useState<User | null>(null);
    // User data in memory, never persisted to localStorage
    return <AuthContext.Provider value={{ user }}>{children}</AuthContext.Provider>;
  }
  ```

---

## External references

- cwe CWE-922
- cwe CWE-312
- owasp A02
- pci-dss Req 6.4.1

Taxons: cryptography-and-secrets

HTML version: https://auditbuffet.com/patterns/ab-001476
