Audit applications and infrastructure handling payment card data against PCI DSS v4.0.1. Heavy emphasis on scope determination (the single most-leveraged variable) plus the engineering-relevant requirements — Req 3 (storage of CHD), Req 4 (transmission), Req 6 (secure SDLC), Req 7-8 (access), Req 10 (logging), Req 11 (testing), Req 12 (program). Use when the user mentions 'PCI,' 'PCI DSS,' 'PCI DSS 4.0,' 'payment card,' 'cardholder data,' 'CHD,' 'PAN,' 'PCI scope,' 'PCI compliance,' 'SAQ,' 'AoC,' 'attestation of compliance,' 'tokenization,' 'P2PE,' 'network segmentation for PCI,' or audits any system that stores, processes, or transmits payment card data.
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
PCI DSS v4.0.1 is the security standard for any environment that stores, processes, or transmits payment card data. Twelve high-level requirements; hundreds of sub-requirements. Most organizations pass or fail on a single decision: scope.
Version note: v4.0.1 (June 2024) is the only active version. v4.0 was retired on 31 December 2024, and the requirements v4.0 marked "future-dated" became mandatory on 31 March 2025. Assess against all of them; don't treat any as best-practice-only.
This skill emphasizes scope determination first, then the engineering-relevant requirements. Final compliance attestation (SAQ self-assessment or QSA audit producing an Attestation of Compliance) is a process this skill prepares for — it is not the attestation itself.
Cross-references: crypto-audit for Req 3 / 4 cryptographic detail; iam-audit for Req 7-8; siem-detection for Req 10 logging; dependency-audit and owasp-audit for Req 6 (secure SDLC); incident-triage for Req 12.10 (incident response); control-audit for program-level control readiness (SOC 2 / ISO 27001) over the same systems.
Audit only environments the user's organization owns or has engaged them to review. Never read, log or paste real card data (PAN, CVV, track data) into the transcript; use test card numbers and trace where cardholder data could flow. If you find real PAN where it shouldn't be, record the location, not the number, and treat it as a possible incident (incident-triage). This is a readiness review, not a QSA assessment.
"Scope" in PCI DSS means: the systems that store, process, or transmit cardholder data (CHD), plus systems that can affect the security of those systems (connected-to and security-impacting systems). Everything in scope is subject to all 12 requirements. Everything out of scope is not.
Most PCI failures are scope failures. A system pulled into scope by accident creates years of compliance debt; a system kept out of scope via good architecture saves substantial cost.
For every system in the environment, classify:
| Type | Definition | In scope? |
|---|---|---|
| CDE (Cardholder Data Environment) | Stores, processes, or transmits PAN, expiration, service code, name when paired with PAN, or sensitive authentication data | Yes — full PCI DSS |
| Connected-to | Has direct connectivity to the CDE without compensating segmentation | Yes |
| Security-impacting | Provides security services to the CDE (auth, logging, monitoring, time sync, DNS) | Yes |
| Segmented | No direct connectivity; segmentation validated annually | No |
| Cardholder data flow only as masked / tokenized | The system handles tokens or masked PANs that cannot be reversed without out-of-band access | Usually No, but verify the token type — surrogate tokens reversible by the merchant are still in scope |
Audit step: trace every payment flow end-to-end. Where does the PAN enter the environment, where does it go, where does it stop. Every system the PAN touches is in scope; every system that touches that system without segmentation is also in scope.
The highest-ROI PCI work is usually scope reduction:
A merchant doing 1M transactions/year via Stripe Checkout with no PAN on their servers is radically less in scope than the same merchant taking PANs into their own form and proxying to Stripe. Same merchant; very different audit.
Briefly, because it sets the audit cadence and rigor:
| Level | Volume (Visa) | Validation requirement |
|---|---|---|
| 1 | > 6M transactions/year, or breached merchant of any volume | Annual on-site QSA assessment → AoC |
| 2 | 1M-6M transactions/year | Annual SAQ (self) or QSA assessment (Visa requires QSA from 2024) |
| 3 | 20K-1M e-commerce transactions/year | Annual SAQ |
| 4 | All other | Annual SAQ |
SAQ types (Self-Assessment Questionnaire) match the merchant's CDE shape — SAQ A (fully outsourced e-commerce), SAQ A-EP (e-commerce that does some redirection), SAQ B (terminal only, dial / IP without electronic storage), SAQ C-VT (web-based virtual terminal), SAQ D (everything else, the longest). The right SAQ is the one whose conditions all match your environment.
The default position: do not store PAN. If you must, encrypt at rest and minimize the data retained.
crypto-audit), key rotation, separation of duties on key custodyAudit grep patterns:
pan, card_number, cc_number, cardnum, account_numberpan, cardNumber, regex ^4[0-9]{12,15}$ (Visa), ^5[1-5][0-9]{14}$ (Mastercard), ^3[47][0-9]{13}$ (Amex), ^6(?:011|5[0-9]{2})[0-9]{12}$ (Discover)console\.log.*cardNumber, logger\..*\.pan, log\..*cardIf a Luhn-valid PAN appears anywhere in source, lock files, or logs, that is a finding regardless of intent, unless it is a published test card number (4242 4242 4242 4242, 4111 1111 1111 1111 and the processor's other documented test PANs).
crypto-audit for the configuration detail)This is where the security audit family meets PCI. Most of this requirement is satisfied by running the existing skills:
owasp-audit, api-auditvuln-research, dependency-audit, finding-triageAudit grep patterns:
--no-verify on commits to prod-impacting branches)See iam-audit for the full identity-and-access deep dive.
See iam-audit for implementation patterns and identity-provider integration.
See siem-detection for the engineering implementation; see soc-operations for the review cadence.
See dependency-audit (vulnerability scan), web-pentest (annual app pentest), red-team-engagement (annual offensive engagement for higher levels).
The program-level layer. Engineering inputs:
incident-triage. Tested at least annuallyClose every candidate with one verdict, as defined in references/findings-format.md, and run the refutation pass in references/verification.md before anything is confirmed.
A gap against a PCI DSS requirement is a finding. The requirement is the intended control. Rate severity by the exposure it creates for cardholder data, using references/severity-calibration.md, not by the audit consequence: CVV written to a reachable table is High or Critical; a missing quarterly ASV scan report is not, by itself, an exposure. A gap with no exposure (a missing policy document, an overdue training record, an annual review not yet done) is a documentation gap: list it in the report's own section, with no severity and no findings.json record. Defense-in-depth gaps where another layer already stops the exposure are hardening notes.
What each verdict looks like here:
confirmed: the code or the exported config shows cardholder data reaching a place the requirement forbids, or a required control missing on a path into the CDE.
logger.info("charge", req.body) in a checkout handler whose form posts cardNumber to the server: PAN written to application logs in clear (Req 3.5.1). The trace runs from the form field to the logger call.LOG_REQUEST_BODIES=true unless overridden, is confirmed with a system_configuration condition ("deployments that don't set LOG_REQUEST_BODIES=false") and confidence medium. A deployment fact you can't see lowers confidence, not the verdict or severity.needs_validation: the code supports the claim and one fact lives outside it. Name it and give the owner the check.
$creditcard; save the settings export to the evidence folder.scripts/seed-from-prod.sh, which calls a sanitizer. Blocker: whether the pipeline that actually runs it passes --sanitize. Check: count (do not print) Luhn-valid 13-19 digit values in the staging payments table.rejected: a named control at a named location rules it out on every path.
paymentMethodId. ruled_out_by.location points at the handler line that reads the body; control names the iframe integration.test/fixtures/cards.json is Stripe's published test PAN. ruled_out_by points at the fixture line and names it as a documented test card.rejected only when the compensating control worksheet exists and the evidence shows the control running; ruled_out_by.location points at the worksheet. A worksheet with no evidence of effectiveness is needs_validation.ruled_out_by.location points at the lockfile or manifest line that pins the version, and control names the library function and version.ruled_out_by.location at the evidence: the only import or call site, or the dependency declaration if nothing uses it.Evidence for deployed resources. Many PCI findings are about things that aren't files: IdP and MFA policies, firewall rules and security groups, log retention settings, a processor's AoC, a written policy. Save the read-only command output or the export, redacted, to <audit dir>/evidence/<name>.json or .txt (for example audit/pci/evidence/okta-cde-policies.json, audit/pci/evidence/sg-cde-ingress.txt) and point location and evidence[] at that file and the relevant line. Process and policy evidence (the incident response plan, a compensating control worksheet, an access review record) goes in the same folder. Never save PAN, CVV, track data, PIN blocks or a credential value in evidence, findings.json or the report; record where the value lives and at most the last 4 digits. Live checks only when authorized and read-only; a check described but not run is needs_validation.
Fingerprints are pci-audit/<class>/<file or resource>/<symbol or name>, slash-separated, with no line numbers. The validator rejects :<digits> segments, so write ARNs and host:port with slashes. Use a short class such as pan-at-rest, sad-stored, pan-in-logs, pan-unmasked, pan-in-lower-env, weak-transmission, pan-in-messaging, shared-account, mfa-gap, access-not-restricted, audit-log-gap, segmentation-gap, scope-misclassified:
pci-audit/pan-in-logs/src/routes/checkout.ts/createCharge
pci-audit/sad-stored/db/schema.sql/payments.cvv
pci-audit/mfa-gap/okta/acme/cde-admin-console
pci-audit/segmentation-gap/aws/123456789012/us-east-1/sg-0abc/ingress-0.0.0.0-0For a deployed resource, build the fingerprint from the resource (provider, account or tenant, name), not from the evidence file name, so it stays the same when the evidence is re-captured.
ext fields (optional object on any record; don't repeat anything that already has a field, such as cwe or location):
| Key | Value | Example |
|---|---|---|
requirement | The PCI DSS v4.0.1 requirement the gap is against | "8.4.2", "3.3.1" |
scope | Scope category of the affected system | "cde", "connected-to", "security-impacting" |
data_element | The cardholder data element exposed, if any | "PAN", "SAD-CVV", "SAD-track", "PIN-block" |
Then:
findings.json sorted by fingerprint, with skill: "pci-audit". Validate it and fix every error: node references/validate-findings.mjs findings.json (references/validate-findings.mjs).node references/to-sarif.mjs findings.json -o findings.sarif (references/to-sarif.mjs).notes.md). They are not records.Dispositions (set later, usually by finding-triage): Fixed / Deferred / Accepted Risk / Mitigated (platform/config) / Requires major migration. PCI accepted risk is heavily disfavored: most "accepted risks" should be compensating controls with documented evidence of effectiveness. A false positive is a rejected record, not a disposition.
Write findings.json first. Render the report from it; the prose never changes a verdict, severity or blocker the JSON doesn't already say.
# PCI DSS v4.0.1 Readiness Review
## Merchant: [name] ## Merchant level: [1/2/3/4] ## SAQ type: [A / A-EP / B / C-VT / D / n/a, Level 1 QSA]
## Date: [date] ## Reviewer: [name] ## Scope: [full | partial, what was left out]
## findings.json: [path], validated: [yes] ## Evidence folder: [path]
### Summary
- Confirmed: [N] (Critical [n] | High [n] | Medium [n] | Low [n]) Needs validation: [N] Rejected: [N]
- Documentation gaps: [N] Hardening notes: [N]
### Confirmed findings
#### [SEVERITY] [Title] `fingerprint`
**Requirement:** [ext.requirement] **Scope:** [ext.scope] **Data element:** [ext.data_element]
**Location:** `path:line` (source or evidence file) **Confidence:** [medium | high (reproduced)]
**What and why it matters:** [the trace or the config evidence, in a few lines; the exposure to CHD]
**Fix:** [concrete change]
**Verify the fix:** [the check that proves it]
### Needs validation
| Finding | Requirement | Blocker | Check for the owner to run |
|---|---|---|---|
### Hardening notes (not findings)
- [gap] — [why it isn't a finding] — [effort]
### Documentation gaps (not findings)
| Requirement | What's missing | Owner | Evidence expected |
|---|---|---|---|
### Rejected (do not re-raise)
| Fingerprint | Ruled out by | Location |
|---|---|---|
### Scope determination
- [ ] Payment data flow diagrammed end-to-end
- [ ] CDE explicitly bounded
- [ ] Connected-to systems enumerated
- [ ] Segmentation evidence documented
- [ ] Scope-reduction opportunities identified
| System | Scope category | Why | Evidence |
|---|---|---|---|
### Per-requirement status
| Req | Confirmed | Needs validation | Documentation gaps |
|-----|-----------|------------------|--------------------|
| 3 — Stored CHD | | | |
| 4 — Transmission | | | |
| 6 — Secure SDLC | | | |
| 7 — Access restriction | | | |
| 8 — Authentication | | | |
| 10 — Logging | | | |
| 11 — Testing | | | |
| 12 — Program | | | |
### Recommended scope reductions (if applicable)
[Hosted payment page, tokenization, network segmentation improvements with effort estimates]
### Compensating controls (if used)
[Each compensating control: control description, what it compensates for, evidence of effectiveness, review cadence, worksheet path]
### Prioritized remediation plan
1. [highest first: SAD storage, PAN in clear, missing CDE MFA]The per-requirement table counts records from findings.json (by ext.requirement) and entries from the documentation-gap list. It is not a separate judgement.
incident-triage — PCI breach response has specific timing and notification requirements (acquirer notification typically within 24 hours)pcisecuritystandards.org/document_libraryreferences/ at build time): references/findings-format.md, references/verification.md, references/severity-calibration.md, references/findings.schema.jsonbriiirussell/cybersecurity-skills
c79bb8b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.