No sensitive payment data stored in localStorage or sessionStorage
Why it matters
Payment tokens (pm_*, tok_*, pi_*) stored in localStorage or sessionStorage are readable by any JavaScript on the page — same-origin scripts, browser extensions, and XSS payloads all have full access. PCI-DSS 4.0 Req 3.3 prohibits storing sensitive authentication data after authorization; CWE-312 (Cleartext Storage of Sensitive Information) and CWE-922 (Insecure Storage of Sensitive Information) both apply. OWASP A02 (Cryptographic Failures) flags browser storage as an insecure persistence layer for payment credentials. Unlike session cookies, localStorage has no expiry and persists across browser restarts, meaning a compromised token can be extracted days or weeks after the initial checkout.
Severity rationale
High because payment tokens persisted in browser storage are indefinitely accessible to any JavaScript on the page, including XSS payloads and browser extensions.
Remediation
Use payment tokens immediately and discard them — never persist them to browser storage. Keep in-flight payment state in React component state only.
// WRONG — token persisted in localStorage
const { paymentMethod } = await stripe.createPaymentMethod({ type: 'card', card: cardElement })
localStorage.setItem('paymentMethodId', paymentMethod.id) // accessible to all scripts
// CORRECT — token used immediately, never stored
const { paymentMethod } = await stripe.createPaymentMethod({ type: 'card', card: cardElement })
await fetch('/api/confirm-payment', {
method: 'POST',
body: JSON.stringify({ paymentMethodId: paymentMethod.id }),
})
// paymentMethod.id is never written to any browser storage
If you need to persist checkout progress across page reloads, store a server-generated session reference in a Secure; HttpOnly cookie — not the payment token itself.
DetectionPro
The detection method for this pattern is part of AuditBuffet Pro.
The full method (what to look for, pass and fail conditions, and how results get reported) ships inside the Payment Security Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- cwe · CWE-312 — Cleartext Storage of Sensitive Information
- cwe · CWE-922 — Insecure Storage of Sensitive Information
- owasp:2021 · A02
- pci-dss:4.0 · Req 3.3 — Sensitive authentication data not retained after authorization
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ecommerce-payment-security·automated