heygrc
PCI DSS Req 3 in code

The card data you must not store.

Requirement 3 is about protecting stored account data, and it draws a hard line. The primary account number, where you do store it, must be rendered unreadable. And sensitive authentication data, the card verification code (the three or four digits), the full magnetic-stripe or chip data, and the PIN, must not be stored after a payment is authorized. For the payment-acceptance flows most applications build, treat that as: you do not keep it, even encrypted. (Card issuers have narrow, controlled exceptions; most teams are not issuers.) The distinction is decided in code, in what your handlers persist.

How it shows up in a diff

The shapes the same control failure takes.

Requirement 3 breaks when a change stores account data it should not, or stores it in the clear. The recurring shapes:

  • Sensitive authentication data is stored

    The card verification code, full track data, or PIN is written to a database, cache, or queue after authorization, which a payment-acceptance flow must not do, even encrypted.

  • A PAN is stored without being unreadable

    A primary account number is persisted with no encryption, truncation, or tokenisation, so it sits readable at rest.

  • Account data lands in a new store

    Card data starts being written to a place not built to protect it (a log, an analytics event, a debug table), pulling that store into scope.

  • A masking or tokenisation step is removed

    A step that truncated or tokenised the PAN before storage is dropped, so the full number is now retained.

  • Card data is kept longer than needed

    A retention or purge that limited how long account data was held is removed, so it accumulates beyond its business need.

Worked example

Saving the card verification code for retries.

A payment occasionally needs a retry, and it would be convenient to re-submit the original details. So a change saves the whole payment payload, including the card verification code, to the orders table. It makes retries easy, and it stores data that must never be kept after authorization.

checkout/orders.ts+1 -1
- await orders.insert({ id, amount, last4: card.last4 })+ await orders.insert({ id, amount, card }) // full card incl. cvcreturn order
heygrcPCI DSS Req 3

Persisting the full card object stores the card verification code after authorization, which Requirement 3 prohibits for a payment-acceptance flow, even if the column is encrypted. Store only what you are allowed to keep (here, the last four digits and a token from your processor), not the verification code, full track, or PIN.

What an auditor does with this

Stored account data is searched for, not just asked about.

A PCI assessment looks at what account data is actually stored and where: it checks that sensitive authentication data is not retained after authorization and that any stored PAN is unreadable. A change that began persisting the verification code or an unmasked PAN is exactly the finding that surfaces, and it pulls whatever store it touched into scope. The diff to the handler is the cheapest place to catch it.

What this is, and is not

A review, not a QSA.

heygrc flags changes that touch Requirement 3 and cites the requirement so the fix happens in the pull request. It does not perform your assessment or complete your Self-Assessment Questionnaire. It catches the moment a change stores account data it should not, at the diff. heygrc is in early access.