DEV Community

Payneteasy
Payneteasy

Posted on

The card number was in our error tracker, not our database

We passed a PCI scoping review on the database side with no issues: no PANs stored, tokens only. Then someone searched our error tracker for a 6-digit BIN while debugging an unrelated decline and got hits.

The cause was boring. A JSON parse error in the checkout handler threw before validation, and the tracker's default integration attached the raw request body to the event. Anything a customer typed into the card field, when the payload was malformed, was stored in plaintext for 90 days. We found 41 events with full 16-digit numbers. All of them came from a mobile client version that sent a trailing comma.

What fixed it:

  1. Scrub at the SDK before send, not in the tracker's UI. Server-side scrubbing still means the data crossed the wire to a third party.
  2. Drop request bodies on payment routes entirely. Keep the route, status, and a request ID.
  3. Add a Luhn-pattern check to the log pipeline as a tripwire. It catches the next leak, not the first one.
  4. Same for reverse proxy access logs if you ever put card data in a query string. Don't.

The part that bothered me most: our scope diagram showed three boxes. The tracker wasn't one of them, because nobody thinks of it as a data store.

Where else have you found cardholder data you didn't expect: APM traces, support tool screenshots, analytics events?

Payneteasy handles this kind of payment flow for merchants and PSPs — see how it works.

Top comments (2)

Collapse
 
crtdrops profile image
Israel Negrete Lepe •

The tripwire in point 3 needs one adjustment if the platform also deals with devices or SIMs. IMEIs are 15 digits with a Luhn check digit, and SIM ICCIDs are 19 to 20 digits, also Luhn, starting with 89. In telemetry and telecom logs they are everywhere, so a bare Luhn match fires all day and people learn to ignore it. Checking card lengths and issuer prefixes as well keeps it quiet enough to stay trusted.

To your question, one box I'd add to that scope diagram: dead-letter queues and retry tables. A failed message is kept whole so it can be replayed, and a malformed payment request is exactly the one that fails.

Collapse
 
robertpaschal profile image
Odinaka Robert Nnamani •

passed the PCI review on the database side and still leaked via the tracker. rough.