Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Testing Browser Storage
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | 159% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 121% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 171% | 0% |
| case-04 | ✓→✓ | = Same ✓ | 181% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 71% | 0% |
WSTG-CLNT-12
Testing Browser Storage
Browser storage mechanisms (localStorage, sessionStorage, IndexedDB, cookies) can store sensitive data client-side. Vulnerabilities occur when sensitive information is stored insecurely, accessible to XSS attacks, or persists longer than necessary. Testing ensures proper data protection and lifecycle management.
javascript// Browser console - Enumerate all storage // Check localStorage console.log("=== localStorage ===") for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i) const value = localStorage.getItem(key) console.log(`${key}: ${value.substring(0, 100)}...`) } // Check sessionStorage console.log("\n=== sessionStorage ===") for (let i = 0; i < sessionStorage.length; i++) { const key = sessionStorage.key(i) const value = sessionStorage.getItem(key) console.log(`${key}: ${value.substring(0, 100)}...`) } // Check cookies console.log("\n=== Cookies ===") document.cookie.split(";").forEach((cookie) => { console.log(cookie.trim()) }) // Check IndexedDB databases console.log("\n=== IndexedDB ===") indexedDB.databases().then((dbs) => { dbs.forEach((db) => console.log(`Database: ${db.name}`)) })
python#!/usr/bin/env python3 """ Browser Storage Security Analyzer Uses Selenium to analyze client-side storage """ from selenium import webdriver from selenium.webdriver.chrome.options import Options import json import time class BrowserStorageTester: def __init__(self, url): self.url = url self.findings = [] self.setup_browser() def setup_browser(self): """Setup headless Chrome""" options = Options() options.add_argument('--headless') options.add_argument('--no-sandbox') self.driver = webdriver.Chrome(options=options) def analyze_storage(self): """Analyze all browser storage""" print(f"[*] Analyzing storage for {self.url}") self.driver.get(self.url) time.sleep(3) # Wait for page load # Get localStorage local_storage = self.driver.execute_script(""" let items = {}; for (let i = 0; i < localStorage.length; i++) { let key = localStorage.key(i); items[key] = localStorage.getItem(key); } return items; """) # Get sessionStorage session_storage = self.driver.execute_script(""" let items = {}; for (let i = 0; i < sessionStorage.length; i++) { let key = sessionStorage.key(i); items[key] = sessionStorage.getItem(key); } return items; """) # Get cookies cookies = self.driver.get_cookies() return { 'localStorage': local_storage, 'sessionStorage': session_storage, 'cookies': cookies } def check_sensitive_data(self, storage_data): """Check for sensitive data patterns""" print("\n[*] Checking for sensitive data...") sensitive_patterns = [ ('password', 'Password'), ('token', 'Authentication Token'), ('api_key', 'API Key'), ('apikey', 'API Key'), ('secret', 'Secret'), ('credit', 'Credit Card'), ('ssn', 'Social Security'), ('session', 'Session Data'), ('auth', 'Authentication Data'), ('bearer', 'Bearer Token'), ('jwt', 'JWT Token'), ('private', 'Private Data'), ] # Check localStorage for key, value in storage_data.get('localStorage', {}).items(): for pattern, description in sensitive_patterns: if pattern.lower() in key.lower() or pattern.lower() in str(value).lower(): print(f"[VULN] Sensitive data in localStorage: {key}") self.findings.append({ "location": "localStorage", "key": key, "issue": f"Potential {description} exposed", "severity": "High" }) # Check sessionStorage for key, value in storage_data.get('sessionStorage', {}).items(): for pattern, description in sensitive_patterns: if pattern.lower() in key.lower() or pattern.lower() in str(value).lower(): print(f"[WARN] Sensitive data in sessionStorage: {key}") self.findings.append({ "location": "sessionStorage", "key": key, "issue": f"Potential {description} exposed", "severity": "Medium" }) # Check cookies for cookie in storage_data.get('cookies', []): name = cookie.get('name', '') for pattern, description in sensitive_patterns: if pattern.lower() in name.lower(): if not cookie.get('httpOnly'): print(f"[VULN] Sensitive cookie without HttpOnly: {name}") self.findings.append({ "location": "cookie", "key": name, "issue": f"{description} cookie without HttpOnly", "severity": "High" }) if not cookie.get('secure'): print(f"[VULN] Sensitive cookie without Secure: {name}") self.findings.append({ "location": "cookie", "key": name, "issue": f"{description} cookie without Secure flag", "severity": "Medium" }) def check_cookie_attributes(self, storage_data): """Check cookie security attributes""" print("\n[*] Checking cookie attributes...") for cookie in storage_data.get('cookies', []): name = cookie.get('name', '') issues = [] if not cookie.get('httpOnly'): issues.append("Missing HttpOnly") if not cookie.get('secure'): issues.append("Missing Secure") if cookie.get('sameSite', '').lower() not in ['strict', 'lax']: issues.append("Missing/Weak SameSite") if issues: print(f"[WARN] Cookie '{name}': {', '.join(issues)}") for issue in issues: self.findings.append({ "location": "cookie", "key": name, "issue": issue, "severity": "Medium" if "HttpOnly" in issue else "Low" }) def test_xss_access(self): """Test if XSS could access storage""" print("\n[*] Testing XSS accessibility to storage...") # Execute XSS-like script to test access result = self.driver.execute_script(""" let accessible = { localStorage: false, sessionStorage: false, cookies: false }; try { localStorage.setItem('xss_test', 'test'); localStorage.removeItem('xss_test'); accessible.localStorage = true; } catch(e) {} try { sessionStorage.setItem('xss_test', 'test'); sessionStorage.removeItem('xss_test'); accessible.sessionStorage = true; } catch(e) {} try { accessible.cookies = document.cookie.length > 0 || true; } catch(e) {} return accessible; """) print(f" localStorage accessible via JS: {result.get('localStorage')}") print(f" sessionStorage accessible via JS: {result.get('sessionStorage')}") print(f" Cookies accessible via JS: {result.get('cookies')}") return result def generate_report(self): """Generate security report""" print("\n" + "="*50) print("BROWSER STORAGE SECURITY REPORT") print("="*50) if not self.findings: print("\nNo significant issues found.") else: high = [f for f in self.findings if f['severity'] == 'High'] medium = [f for f in self.findings if f['severity'] == 'Medium'] low = [f for f in self.findings if f['severity'] == 'Low'] if high: print(f"\n[HIGH SEVERITY] ({len(high)} issues)") for f in high: print(f" - {f['location']}/{f['key']}: {f['issue']}") if medium: print(f"\n[MEDIUM SEVERITY] ({len(medium)} issues)") for f in medium: print(f" - {f['location']}/{f['key']}: {f['issue']}") if low: print(f"\n[LOW SEVERITY] ({len(low)} issues)") for f in low: print(f" - {f['location']}/{f['key']}: {f['issue']}") def run_tests(self): """Run all tests""" try: storage_data = self.analyze_storage() print("\n[*] Storage Contents:") print(f" localStorage entries: {len(storage_data.get('localStorage', {}))}") print(f" sessionStorage entries: {len(storage_data.get('sessionStorage', {}))}") print(f" Cookies: {len(storage_data.get('cookies', []))}") self.check_sensitive_data(storage_data) self.check_cookie_attributes(storage_data) self.test_xss_access() self.generate_report() finally: self.driver.quit() # Usage tester = BrowserStorageTester("https://target.com") tester.run_tests()
javascript// Analyze IndexedDB contents async function analyzeIndexedDB() { const databases = await indexedDB.databases() for (const dbInfo of databases) { console.log(`\n=== Database: ${dbInfo.name} ===`) const request = indexedDB.open(dbInfo.name) request.onsuccess = function (event) { const db = event.target.result const storeNames = db.objectStoreNames console.log("Object Stores:", Array.from(storeNames)) for (const storeName of storeNames) { const transaction = db.transaction(storeName, "readonly") const store = transaction.objectStore(storeName) const getAllRequest = store.getAll() getAllRequest.onsuccess = function () { console.log(`\nStore: ${storeName}`) console.log("Records:", getAllRequest.result.length) // Check for sensitive data getAllRequest.result.forEach((record, i) => { const str = JSON.stringify(record) if (str.match(/password|token|secret|key|auth/i)) { console.log(`[!] Potential sensitive data in record ${i}`) } }) } } } } } analyzeIndexedDB()
bash#!/bin/bash TARGET="https://target.com" # Fetch and analyze cookies echo "[*] Analyzing cookies for $TARGET" curl -sI "$TARGET" | grep -i "set-cookie" | while read -r line; do echo "" echo "Cookie: $line" # Check security attributes if ! echo "$line" | grep -qi "httponly"; then echo " [!] Missing HttpOnly" fi if ! echo "$line" | grep -qi "secure"; then echo " [!] Missing Secure" fi if ! echo "$line" | grep -qi "samesite"; then echo " [!] Missing SameSite" fi done
| Tool | Purpose | | ---------------------------------- | -------------------------- | | Browser DevTools (Application tab) | View all storage | | EditThisCookie | Cookie editor extension | | Selenium/Puppeteer | Automated storage analysis | | Burp Suite | Cookie analysis |
javascript// SECURE: Don't store sensitive data in localStorage // Use server-side sessions instead // If client storage is needed, encrypt sensitive data class SecureStorage { constructor(encryptionKey) { this.key = encryptionKey; } async encrypt(data) { const encoder = new TextEncoder(); const encodedData = encoder.encode(JSON.stringify(data)); const cryptoKey = await crypto.subtle.importKey( 'raw', encoder.encode(this.key), { name: 'AES-GCM' }, false, ['encrypt'] ); const iv = crypto.getRandomValues(new Uint8Array(12)); const encrypted = await crypto.subtle.encrypt( { name: 'AES-GCM', iv }, cryptoKey, encodedData ); return { iv: Array.from(iv), data: Array.from(new Uint8Array(encrypted)) }; } async setItem(key, value) { const encrypted = await this.encrypt(value); sessionStorage.setItem(key, JSON.stringify(encrypted)); } } // SECURE: Set proper cookie attributes // Server-side (Python/Flask) from flask import make_response @app.route('/login', methods=['POST']) def login(): response = make_response(redirect('/dashboard')) response.set_cookie( 'session_id', value=generate_session_id(), secure=True, # HTTPS only httponly=True, # No JavaScript access samesite='Strict', # No cross-site requests max_age=3600, # 1 hour expiry path='/', domain='.example.com' ) return response // SECURE: Clear storage on logout function secureLogout() { // Clear all storage localStorage.clear(); sessionStorage.clear(); // Clear IndexedDB indexedDB.databases().then(dbs => { dbs.forEach(db => indexedDB.deleteDatabase(db.name)); }); // Clear cookies (server should also invalidate) document.cookie.split(';').forEach(cookie => { const name = cookie.split('=')[0].trim(); document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`; }); // Redirect to login window.location.href = '/login'; }
| Finding | CVSS | Severity | | --------------------------------------- | ---- | -------- | | Credentials in localStorage | 7.5 | High | | Session token in localStorage | 7.5 | High | | Sensitive cookie without HttpOnly | 6.1 | Medium | | Missing Secure flag on sensitive cookie | 5.3 | Medium | | PII in browser storage | 5.3 | Medium |
| CWE ID | Title | | ------------ | ------------------------------------------------------------ | | CWE-922 | Insecure Storage of Sensitive Information | | CWE-312 | Cleartext Storage of Sensitive Information | | CWE-1004 | Sensitive Cookie Without 'HttpOnly' Flag | | CWE-614 | Sensitive Cookie in HTTPS Session Without 'Secure' Attribute |
[ ] localStorage analyzed
[ ] sessionStorage analyzed
[ ] IndexedDB databases enumerated
[ ] Cookie attributes checked
[ ] Sensitive data patterns searched
[ ] XSS accessibility tested
[ ] Data persistence after logout tested
[ ] Findings documentedOther measured skills in the registry, with their headline benchmark lift.