No credit card data stored in application database
Why it matters
Storing raw card numbers, CVV, or full PANs in your database is a direct violation of PCI DSS Req 3.3.1 and Req 3.5.1 (pci-dss:4.0), classified under OWASP A02 (Cryptographic Failures) and CWE-312 (Cleartext Storage of Sensitive Information). A single database breach exposes every stored card to attackers. Payment providers deliberately design their systems so your application never needs to hold this data — storing it anyway buys you nothing except unlimited liability.
Severity rationale
Critical because any stored raw card data is immediately exploitable in a breach and constitutes a per-se PCI DSS violation regardless of encryption.
Remediation
Remove all raw card columns from your schema and replace them with provider-issued opaque identifiers. If you need to display card details to users (last 4 digits, brand), fetch that information from the provider's API at render time.
// prisma/schema.prisma — replace card_number / cvv columns with:
model User {
stripe_customer_id String? @unique
stripe_default_payment_method String?
// card_number String <-- delete this
// cvv String <-- delete this
}
To show "Visa ending in 4242" on the billing page, call stripe.paymentMethods.retrieve(pm.id) and read pm.card.last4 and pm.card.brand — never cache those values to your own database.
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 Billing & Payments Audit. The pattern definition, severity rationale, and remediation remain openly licensed under CC-BY-4.0.
External references
- pci-dss:4.0 · Req 3.3.1 — SAD must not be retained after authorization
- pci-dss:4.0 · Req 3.5.1 — PAN must be rendered unreadable anywhere it is stored
- cwe · CWE-312 — Cleartext Storage of Sensitive Information
- owasp:2021 · A02 — Cryptographic Failures
Taxons
History
- 2026-04-18·v1.0.0·Initial import from saas-billing·automated