The Storage Panel
🗄️ Lesson 6 — The Storage Panel
The Storage panel shows everything the browser is holding on behalf of the current site — cookies, localStorage, sessionStorage, IndexedDB, and the Service Worker cache — with the ability to read, add, edit, and delete entries directly. Open it with Shift + F9.
🗺️ The Storage Panel Interface
| Name | Value | Domain | Path | Expires | HttpOnly | Secure | SameSite |
|---|---|---|---|---|---|---|---|
| session_id | eyJhbGci…Xk3Q | example.com | / | 2024-12-31 | ✓ | ✓ | Strict |
| _ga | GA1.2.1234567 | .example.com | / | 2026-01-01 | — | — | Lax |
| theme_pref | dark | example.com | / | Session | — | — | Lax |
| tracking_id | abc123 | .example.com | / | 2025-06-01 | — | — | None ⚠ |
The session_id row (highlighted) is a well-configured session cookie — HttpOnly ✓, Secure ✓, SameSite Strict. The tracking_id cookie has SameSite=None without the Secure flag — a misconfiguration that modern browsers will reject.
🍪 Cookies
Cookies are small key-value pairs the server sends via Set-Cookie headers. The browser automatically attaches them to every matching request — making them the standard mechanism for session authentication.
Security Flags
These three flags are the most important columns when auditing cookie security:
document.cookie. The primary defence against XSS attacks stealing the session token — even injected scripts can't touch it.SameSite Values
Editing Cookies in DevTools
Delete a cookie: select a row → press Delete, or right-click → Delete Cookie.
Add a cookie: click the empty row at the bottom of the table and type a name and value.
Try setting the session cookie value to
INVALID and making an API call — the server should return 401. If it returns 200, the server isn't validating tokens.
eyJ… string). Paste it into jwt.io in a browser. The payload is decoded instantly — you can read the sub, exp, role claims without any code. Remember: a JWT is signed, not encrypted — the payload is readable by anyone who has it.
📦 Local Storage
A persistent key-value store tied to the current origin. Data survives browser restarts indefinitely — there is no expiry. Values are always strings; objects are stored as JSON.
localStorage is readable by any JavaScript on the same origin. An XSS attack that injects a script can steal everything in localStorage — including authentication tokens. The
auth_token entry shown above is a common anti-pattern. Auth tokens belong in HttpOnly cookies, which JavaScript (including injected scripts) cannot read.
Interact with localStorage from the Console without touching the Storage panel:
// Read a value
localStorage.getItem('theme') // → "dark"
// Write a value
localStorage.setItem('theme', 'light')
// Delete one key
localStorage.removeItem('auth_token')
// List all keys and values
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
console.log(key, localStorage.getItem(key));
}
🕐 Session Storage
Identical API to localStorage, but scoped to a single browser tab and cleared when that tab closes. Two tabs open on the same page have completely separate sessionStorage.
| Behaviour | localStorage | sessionStorage |
|---|---|---|
| Survives page reload | ✓ | ✓ |
| Survives browser restart | ✓ | ✗ |
| Survives tab close | ✓ | ✗ |
| Shared between tabs (same origin) | ✓ | ✗ — per tab |
| Good for multi-step form state | Risky — persists after close | ✓ Ideal |
🗃️ IndexedDB
A full client-side database — asynchronous, transactional, and capable of storing structured JavaScript objects, Blobs, and large datasets. Used by PWAs for offline support and by apps that need complex queries over cached data.
⚡ Cache Storage
Service Worker-controlled storage for complete HTTP request/response pairs. Unlike the browser's own HTTP cache, this is entirely under application control — a Service Worker script decides what to cache and what to return offline.
📊 Storage Types at a Glance
| Storage Type | Controlled by | Stores | Max Size | Survives Tab Close | JS Readable |
|---|---|---|---|---|---|
| Cookies | Server + JS | Strings (4 KB each) | ~4 KB / cookie | Until expires | Only if not HttpOnly |
| localStorage | JavaScript | Strings | ~5–10 MB | ✓ | ✓ (XSS risk) |
| sessionStorage | JavaScript | Strings | ~5 MB | ✗ | ✓ (XSS risk) |
| IndexedDB | JavaScript | Structured objects, Blobs | ~50% of disk | ✓ | ✓ |
| Cache Storage | Service Worker | HTTP request/response pairs | ~50% of disk | ✓ | ✓ (SW only) |
📏 Checking Storage Quota
Run this in the Console to see how much storage the current origin is using:
const est = await navigator.storage.estimate();
console.log(`Used: ${(est.usage / 1024 / 1024).toFixed(2)} MB`);
console.log(`Quota: ${(est.quota / 1024 / 1024).toFixed(0)} MB`);
When storage fills up, writes to localStorage/sessionStorage throw a QuotaExceededError. IndexedDB and Cache Storage may be evicted by the browser under disk pressure unless the origin has called navigator.storage.persist().
✏️ Exercises
-
Audit cookie security. Open the Storage panel (
Shift + F9) on a site you're logged into. Find the session cookie. Are HttpOnly, Secure, and SameSite all set? Note any cookies that are missing flags they should have. -
Decode a JWT. Copy a JWT cookie value (the
eyJ…string) and paste it into jwt.io. Read the decoded payload — what claims does it include? Note theexptimestamp and convert it to a human-readable date. -
Test an expired session. In the Storage panel, edit the session cookie value to
INVALID. Reload the page or trigger an API call. Does the server return 401? Restore the original value. - Explore localStorage. Open localStorage for any site. Are any values stored as JSON? Double-click a value to edit it — change a preference (theme, language, etc.) and reload. Does the page reflect the change?
- Verify sessionStorage isolation. Open two tabs on the same page. In the first tab's Storage panel, add a key to sessionStorage. Open the Storage panel in the second tab — confirm the key is not there.
-
Check your storage quota. Run this in the Console:
navigator.storage.estimate().then(e => console.log(`${(e.usage/1024/1024).toFixed(2)} MB used of ${(e.quota/1024/1024).toFixed(0)} MB`)); - Test logout cleanup. Log into a site and note what cookies and localStorage keys exist. Click the logout button. Open the Storage panel — are the session cookie and any user-specific localStorage entries gone? Any that remain after logout are a potential security issue.
📌 Key Takeaways
- Session cookies must have HttpOnly (no JS access), Secure (HTTPS only), and SameSite=Lax or Strict (CSRF protection).
- localStorage is persistent and origin-scoped but readable by any JS — never store auth tokens here; use HttpOnly cookies.
- sessionStorage is identical to localStorage but cleared on tab close — ideal for temporary, tab-specific state like multi-step forms.
- IndexedDB is a full client-side database for structured data and large volumes; used by PWAs for offline support.
- Cache Storage is Service Worker-controlled — it stores complete HTTP responses and is the backbone of offline-capable apps.
- Edit cookie values directly in the Storage panel to test auth flows — set a token to INVALID to verify the server rejects it.
- After logout, check the Storage panel — all session data should be gone. Leftover tokens in any storage are a security bug.