heygrc
PCI DSS Req 10 in code

The access log cardholder data can't skip.

Requirement 10 is the audit-trail requirement: implement logging so that access to system components and cardholder data can be linked to an individual user and reconstructed later if something goes wrong. It is not enough that the application logs something; the requirement is specifically about individual user access to cardholder data, each entry carrying who, what, when, from where, and whether it succeeded, and the log itself has to be protected from being altered after the fact. A meaningful part of that is decided in code: the path that reads or writes account data, the middleware that logs a request, and whether a new way of touching that data was wired through the logged path at all.

How it shows up in a diff

The shapes the same control failure takes.

Requirement 10 breaks less often by deleting an existing log line than by adding a new way to reach cardholder data that never had one. The recurring shapes:

  • A new path to cardholder data skips the log

    A support tool, script, or admin route reads cardholder data directly (a database client, a raw query) instead of through the application path that logs the access, so the application's audit trail has no user-attributed record of it.

  • A log entry loses who did it

    An access is still logged, but the actor is recorded as a service or system identifier instead of the individual user, so it can no longer be linked to a person.

  • A required field drops out of the entry

    A log entry stops carrying one of the fields the requirement expects (the event type, the date and time, success or failure, the resource affected), thinning the record below what an investigation needs.

  • Log integrity protection is removed

    A control that kept audit logs from being altered or deleted (restricted write permissions, centralized shipping) is loosened, so the trail itself becomes editable.

  • A new component ships outside the logging pipeline

    A new system component that touches cardholder data is stood up without being wired into the centralized logging the rest of the cardholder data environment uses.

Worked example

A support script that reads cardholder data straight from the database.

Support needs to check a customer's saved-card status for an open ticket. The app's API path logs every cardholder-data access against the requesting user, but writing a proper support endpoint takes longer than the ticket queue can wait, so a script is added that connects a support engineer's own database credentials directly to the payments database and queries the cards table. It resolves the ticket, and cardholder data can now be read this way without going through the application's audit trail, so the access is not tied to the specific customer record it touched.

scripts/support/lookup-card.ts+4 -0
// support script: check a customer's saved-card status+ const db = await connect(process.env.PAYMENTS_DB_URL)+ const [card] = await db.query("SELECT status FROM cards WHERE customer_id = $1", [customerId])+ console.log(card)+ // ad hoc, run locally when support needs a lookup
heygrcPCI DSS Req 10

This script reads the cards table directly, outside the application path that logs cardholder-data access against a named user. Requirement 10 expects individual access to cardholder data to be logged and attributable, and running a query straight against the database does not produce that record in the application's audit trail. Add a logged, permissioned support endpoint for this lookup instead of direct database access, so it shows up in the same audit trail as everything else.

What an auditor does with this

Requirement 10 is checked by trying to reconstruct an access.

An assessor tests Requirement 10 by picking an instance of cardholder-data access and asking whether the logs can show who did it, when, and whether it succeeded, and whether those logs could have been altered afterward. A support script or a new component that reads cardholder data outside the logged path is exactly the gap that surfaces: an access that happened with nothing in the application's audit trail to reconstruct it from. It usually starts as a shortcut to unblock one ticket or one migration.

What this is, and is not

A review, not your SIEM.

heygrc flags changes that touch Requirement 10 and cites the requirement so the fix happens in the pull request. It does not run your log aggregation or your log review process. It catches the moment a change opens a path to cardholder data that the audit trail does not cover, at the diff.