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.
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.
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:
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.
finserv-session-security.session-integrity.session-data-not-local-storagelow"1 localStorage.setItem('authToken', ...) found in src/lib/auth.ts:23 — session token exposed to XSS"src/lib/auth.ts or src/context/AuthContext.tsx):
// 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>;
}