← Back to All Vulnerabilities

Local Storage Vulnerabilities

Browser storage mechanisms like localStorage and sessionStorage are convenient for storing data on the client side but can expose sensitive information if used improperly. This demo shows how insecure use of browser storage can lead to security issues.

Understanding Browser Storage

1. Types of Browser Storage

2. Key Security Differences

Feature localStorage sessionStorage Cookies
Persistence Permanent until cleared Tab session only Configurable expiration
Size Limit ~5-10MB ~5-10MB ~4KB
Sent with Requests No No Yes (increases request size)
HttpOnly Flag No (always accessible to JS) No (always accessible to JS) Yes (can block JS access)
Secure Flag No No Yes (HTTPS only)
SameSite Attribute No No Yes (controls cross-site sending)

3. Common Vulnerabilities

Browser Storage Vulnerabilities Demonstration

Login Form (Insecure)

This form demonstrates insecure storage of sensitive data in localStorage.

My App

Logged Out

Current localStorage Contents:

No data in localStorage yet.

Browser Console (try these commands):

> localStorage.getItem('user_credentials')

No data stored yet.

Security Issues:

  • Plaintext Credentials - Email and password stored as plaintext JSON in localStorage
  • Persistent Storage - Credentials remain even after session ends
  • JavaScript Access - Any script on this domain can access the stored credentials
  • XSS Vulnerability - If the site is vulnerable to XSS, the attacker can steal stored credentials

Try this: After logging in, execute localStorage.getItem('user_credentials') in your browser console to see your saved credentials.

Login Form (Secure)

This form demonstrates more secure ways to store authentication data.

My App (Secure)

Logged Out

Current Storage Contents:

No data in storage yet.

Browser Console:

> localStorage.getItem('auth_token')

No data stored yet.

Security Improvements:

  • No Sensitive Data - Password is never stored
  • Token-based Authentication - Only a temporary authentication token is stored
  • HttpOnly Cookies - When using cookies, the HttpOnly flag prevents JavaScript access
  • Secure Flag - The Secure flag ensures cookies are only sent over HTTPS
  • Session-only Option - Using sessionStorage clears data when the tab is closed

XSS Amplification via localStorage

This demo shows how localStorage can amplify XSS attacks by storing malicious payloads that execute on every page load.

User Preferences

Live Preview

Your preferences will be applied here.

XSS Payloads to Try:

Enter these in the "Custom CSS" field:

  1. } to break out of the CSS context
  2. } <img src=x onerror="alert('XSS via localStorage')">
  3. } <script>document.body.innerHTML = "Site hacked via localStorage"</script>

These payloads will be stored in localStorage and executed on every page load, amplifying the XSS attack.

Browser Storage Inspector

This tool shows you the current contents of localStorage, sessionStorage, and cookies in your browser for this domain.

localStorage:

sessionStorage:

Cookies:

Inspecting Storage in Production:

Using browser developer tools, you can inspect storage in any website:

  1. Open Developer Tools (F12 or right-click → Inspect)
  2. Go to the "Application" tab in Chrome or "Storage" tab in Firefox
  3. Expand the "Storage" section to see localStorage, sessionStorage, and Cookies

Many websites store sensitive information in client-side storage. Always check what data is stored when performing security audits.

How to Secure Browser Storage

1. Never Store Sensitive Data

The safest approach is to avoid storing sensitive data in client-side storage entirely:

2. Use HttpOnly Cookies for Authentication

For authentication tokens, HttpOnly cookies offer better protection:

// Setting an HttpOnly cookie in PHP
setcookie('auth_token', $token, [
    'expires' => time() + 3600,
    'path' => '/',
    'domain' => 'example.com',
    'secure' => true,    // HTTPS only
    'httponly' => true,  // Inaccessible to JavaScript
    'samesite' => 'Strict' // No cross-site sending
]);

// Setting an HttpOnly cookie in Node.js with Express
res.cookie('auth_token', token, {
    maxAge: 3600000,
    httpOnly: true,
    secure: true,
    sameSite: 'strict'
});
        

3. Use Short-lived Tokens

If you must store authentication data in localStorage or sessionStorage, use short-lived tokens:

// Store only short-lived tokens, not credentials
localStorage.setItem('auth_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');

// Check for token expiration before use
function getStoredToken() {
    const tokenData = JSON.parse(localStorage.getItem('auth_token'));
    if (tokenData && new Date() < new Date(tokenData.expiresAt)) {
        return tokenData.token;
    }
    return null; // Expired or not found
}
        

4. Use sessionStorage Instead of localStorage

sessionStorage is cleared when the tab is closed, reducing the persistence of any sensitive data:

// Using sessionStorage instead of localStorage
sessionStorage.setItem('temp_data', JSON.stringify({
    userId: 123,
    username: 'user123',
    sessionExpiresAt: new Date().getTime() + (60 * 60 * 1000) // 1 hour
}));
        

5. Encrypt Sensitive Data

If you absolutely must store sensitive data, encrypt it before storing:

// Using the Web Crypto API to encrypt data before storage
async function encryptAndStore(key, data) {
    const encoder = new TextEncoder();
    const dataBuffer = encoder.encode(JSON.stringify(data));
    
    // Generate a random initialization vector
    const iv = crypto.getRandomValues(new Uint8Array(12));
    
    // Encrypt the data
    const encryptedData = await crypto.subtle.encrypt(
        { name: 'AES-GCM', iv },
        key,
        dataBuffer
    );
    
    // Store the encrypted data and IV
    localStorage.setItem('encrypted_data', JSON.stringify({
        iv: Array.from(iv),
        data: Array.from(new Uint8Array(encryptedData))
    }));
}
        

6. Validate and Sanitize Stored Data

Always validate and sanitize data when retrieving it from storage to prevent stored XSS:

// Sanitize data retrieved from storage
function getSafePreference(key) {
    const data = localStorage.getItem(key);
    if (!data) return null;
    
    // Use a library like DOMPurify
    return DOMPurify.sanitize(data);
}

// Apply preferences safely
document.getElementById('userPreferences').innerHTML = getSafePreference('customCSS');
        

7. Implement Proper Logout

Always clear stored data during logout:

function logout() {
    // Clear localStorage
    localStorage.removeItem('auth_token');
    localStorage.removeItem('user_preferences');
    
    // Clear sessionStorage
    sessionStorage.clear();
    
    // Expire cookies
    document.cookie = 'auth_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    
    // Redirect to login page
    window.location.href = '/login';
}