Agent Wranglers

APP-76Required

Keep tokens and sensitive data out of browser storage

Keep access tokens, passwords, card data, government ID numbers and health data out of localStorage, sessionStorage and IndexedDB. Delete every draft and offline copy an account stored when it signs out.

How to do it

Any script on the page can read browser storage, so one cross-site scripting hole hands all of it to an attacker. Anyone who uses the same device can read it too. Keep the session in an HttpOnly cookie, as session cookies says. Store drafts and offline queues under keys that start with the user's ID, and keep only the fields the screen needs. Prefer sessionStorage when the data need not outlive the tab. On sign-out, delete those keys and IndexedDB stores, then send the header from wipe browser data on sign-out. Validate what you read back like any other input. Native apps keep tokens in the system store instead, as Keep tokens and keys in the Keychain or Keystore says.

Examples

TypeScript example

export async function forgetUserOnThisDevice(userId: string) {
  for (const storage of [localStorage, sessionStorage]) {
    for (const key of Object.keys(storage)) if (key.startsWith(`${userId}:`)) storage.removeItem(key);
  }
  for (const { name } of await indexedDB.databases()) {
    if (name?.startsWith(`${userId}:`)) indexedDB.deleteDatabase(name);
  }
}

Python example

TOKEN_PATTERN = re.compile(r"eyJ[\w-]+\.[\w-]+\.|Bearer |\b\d{13,19}\b")

def test_browser_storage_holds_no_secrets(signed_in_page):
    signed_in_page.goto("https://app.example.com/invoices/new")
    signed_in_page.get_by_label("Customer").fill("Northwind Traders")
    dump = signed_in_page.evaluate("JSON.stringify([{...localStorage}, {...sessionStorage}])")
    assert not TOKEN_PATTERN.search(dump)

How to check

A browser test signs in, opens every screen with a draft or offline feature and dumps localStorage, sessionStorage and every IndexedDB store. The dump holds 0 tokens, JWTs, card numbers or test ID numbers. After sign-out, it holds 0 keys for that user.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/app-ui/client-and-server-state/sensitive-data-out-of-browser-storage">Agent Wranglers web app interface playbook</a>. In code you write, add a comment next to it with the same link.