Payment Card Security

PCI DSS Cardholder Data Discovery

Primary account numbers do not stay where you put them. Learn how to define CHD and SAD precisely, find stray PANs in logs, tickets, and databases, shrink your PCI scope with detection-plus-masking, and operationalize the quarterly discovery scans assessors expect.

Explore the Guide

CHD and SAD, Precisely Defined

PCI DSS — now at version 4.0.1, mandatory since March 2024 with the remaining future-dated requirements enforceable from March 31, 2025 — protects a narrowly defined asset: account data. Account data splits into two classes with very different rules. Cardholder data (CHD) is the primary account number (PAN) alone, or the PAN together with cardholder name, expiration date, and service code. Sensitive authentication data (SAD) is the security-critical material used to authorize transactions: full track data from the magnetic stripe or chip, the card verification code (CVV2/CVC2/CID), and PINs or PIN blocks.

The distinction drives everything. CHD may be stored if there is a documented business need, but the PAN must be rendered unreadable at rest — via strong cryptography, truncation, tokenization, or one-way hashing — and masked when displayed, showing at most the first six (or eight, under 4.0's expanded BIN rules) and last four digits. SAD, by contrast, must never be stored after authorization, even encrypted, with the sole exception of issuers with a documented justification. A single CVV sitting in a database column after authorization completes is an automatic compliance failure, no matter how well encrypted the column is.

Note what makes discovery hard: the PAN is the pivot element. Cardholder name or expiration date stored without the PAN is not cardholder data at all under the standard. The same name stored next to a PAN becomes CHD requiring full protection. So a discovery program cannot simply grep for names; it must find PANs first, then evaluate what travels with them. That is a contextual judgment — exactly the kind of judgment a transformer-based detection model makes and a regex does not.

Our PII Detection API detects CREDIT_CARD_NUMBER (with Luhn validation and issuer-range awareness to suppress false positives from order IDs and timestamps), CREDIT_CARD_EXPIRATION_DATE, CVV_NUMBER, and PERSON_NAME as distinct entity types, each with character offsets and confidence scores — the raw material for both discovery reports and automated remediation.

Zero-tolerance rule: SAD storage after authorization is prohibited outright. If a discovery scan finds a CVV in any log, ticket, or table, the finding is not "encrypt it" — it is "delete it, fix the process that captured it, and document both."

Account Data Elements: Storage Rules and Detection Mapping

This table condenses the PCI DSS account-data matrix and maps each element to the API entity type that finds it. Use the entity list as your entities parameter for payment-focused scans; the full catalog is on the entities page.

Data element Class Storage permitted? Protection required API entity type
Primary Account Number (PAN) CHD Yes, with business need Render unreadable at rest (Req 3.5); mask on display (Req 3.4) CREDIT_CARD_NUMBER
Cardholder name CHD (with PAN) Yes Protect when stored with PAN PERSON_NAME
Expiration date CHD (with PAN) Yes Protect when stored with PAN CREDIT_CARD_EXPIRATION_DATE
Service code CHD (with PAN) Yes Protect when stored with PAN Detected in track-data context
Full track data (magstripe / chip equivalent) SAD No (post-authorization) Must not be retained; secure deletion on discovery CREDIT_CARD_NUMBER + adjacent track markers
CVV2 / CVC2 / CID SAD No (post-authorization) Must not be retained, even encrypted CVV_NUMBER
PIN / PIN block SAD No (post-authorization) Must not be retained PASSWORD in PIN context
Bank account / IBAN (non-card payments) Out of PCI scope, in privacy scope Regulated by GDPR/CCPA/GLBA Detect and protect under privacy program FINANCIAL_ACCOUNT_NUMBER, IBAN_CODE, ROUTING_NUMBER

One subtlety worth internalizing: truncated PANs (first six/eight plus last four) and properly tokenized values are not cardholder data, so systems that hold only those forms can drop out of scope. That is the mechanical basis of every descoping strategy discussed below — replace the PAN with something that is not a PAN, everywhere the full value is not strictly required.

Requirement 3 and the Scoping Problem

Requirement 3 — "Protect stored account data" — is where discovery becomes an explicit obligation rather than good hygiene. Requirement 3.2.1 demands that account data storage be kept to the minimum necessary, with documented retention periods and quarterly processes to securely delete data exceeding retention. Requirement 3.3 prohibits SAD retention. And critically, PCI DSS 4.0's Requirement 12.5.2 requires entities to document and confirm their PCI DSS scope at least every twelve months — an exercise that the standard explicitly says must include identifying all locations where account data is stored, processed, and transmitted, including where it might have leaked outside the defined cardholder data environment (CDE).

Scope is the economic heart of PCI. Every system that stores, processes, or transmits CHD — plus every system connected to or capable of affecting the security of those systems — is in scope for all applicable requirements: segmentation, hardening, logging, vulnerability management, access control, and assessment. A stray PAN in a marketing database does not just create risk; it drags that database, its host, its admins, and potentially its network segment into your assessment. QSAs have a phrase for the recurring nightmare: "scope creep by data leakage."

The scoping confirmation is therefore a data-discovery exercise in disguise. You must be able to demonstrate, with evidence, that no account data exists outside the CDE — and the only credible evidence is the output of scans that actually looked. Network diagrams and dataflow interviews establish where card data is supposed to be; discovery scans establish where it is. Assessors under 4.0 increasingly ask for both, and for the reconciliation between them.

Detection-based discovery serves both sides of this: sweep the systems believed to be out of scope to prove the negative, and sweep the CDE itself to verify that retention limits and SAD prohibitions hold in practice. Findings feed Requirement 3's quarterly deletion process and Requirement 12's annual scope confirmation from a single pipeline.

4.0 change to note: Requirement 12.5.2's periodic scope confirmation is no longer implicit good practice — it is a defined, evidenced requirement (every 12 months for merchants, every 6 for service providers). Ad-hoc discovery no longer passes; you need a repeatable, documented scanning process.

Where PANs Actually Hide

Twenty years of forensic breach reports agree: compromised card data is rarely stolen from the payment database. It is harvested from the places nobody thought to protect because nobody knew the PANs were there.

Application and Web Server Logs

Debug logging of full request bodies, error handlers that dump form payloads, and gateway timeout retries that serialize the transaction all write PANs to disk in plaintext. Log shippers then replicate them to aggregators, index them for search, and archive them to object storage — multiplying one leak into five in-scope systems. Scanning the log stream at ingestion catches the leak at hop one.

Support Tickets and Chat Transcripts

Customers paste full card numbers into chat when a payment fails; agents copy them into ticket notes to retry the charge. The helpdesk platform — a SaaS tool far outside your CDE diagram — now stores CHD, and sometimes CVVs, indefinitely. Real-time detection on ticket and chat ingestion, with automatic masking, is the only control that scales with agent behavior.

Databases Beyond the Payment Schema

Free-text columns are the classic offenders: order notes, CRM comments, fraud-review annotations, and imported legacy data. So are analytics replicas and data-lake copies of "sanitized" tables that were sanitized before the leak began. Column-level sampling with entity detection finds PANs in fields whose names give no hint — see our database discovery guide.

Email, Spreadsheets, and File Shares

Reconciliation spreadsheets exported by finance, chargeback evidence emailed by processors, call-center quality recordings transcribed to text, and screenshots in shared drives. These unmanaged copies are the reason 4.0 scoping language says "including where account data might exist outside the CDE." Document and email scanning brings them into the discovery net.

Descoping with Detection Plus Masking

The cheapest PCI control is the one you no longer need. Every system you can demonstrate holds no account data exits the assessment: no quarterly ASV scans against it, no compensating controls, no sampling during the audit. The descoping playbook has two moves — stop new account data from entering non-CDE systems, and eliminate what already leaked in — and detection powers both.

Move one: inline prevention. Put a detection-and-masking step at the choke points where free text crosses into non-CDE systems: the logging library or log shipper, the ticket-creation webhook, the chat-message pipeline, the ETL jobs feeding the warehouse. Configure the scan for payment entities and use mask_mode to neutralize hits before they are written. A masked value — [CREDIT_CARD_NUMBER] or a last-four-preserving token — is not CHD, so the receiving system stays out of scope by construction. Latency is a single API round-trip, and batching keeps cost negligible; see pricing for volume tiers.

Move two: retrospective cleanup. Sweep historical stores — log archives, ticket backlogs, database columns, mailboxes — and remediate findings: secure deletion for SAD, masking or truncation for PANs where the record must survive, cryptographic protection where full PANs are genuinely required (which almost always means "move it into the CDE instead"). The scan report itself, showing zero residual findings, becomes the assessor-facing evidence that the system is clean.

Tokenization services and point-to-point encryption shrink scope at the payment flow's front door; detection-plus-masking shrinks it everywhere else — the exhaust paths the payment architecture diagrams never show. Mature programs run both, and their PCI assessments cover a fraction of the infrastructure they did before.

Practical note: masking with the hash mode preserves record linkage — the same PAN always yields the same token — so fraud analytics and customer-support dedup keep working on descoped data. Use replace or redact where no linkage is needed; less structure means less residual risk.

Quarterly and Continuous Discovery Scans

PCI's rhythm section: Requirement 3.2.1's quarterly purge of over-retained data, Requirement 12.5.2's annual (or semi-annual) scope confirmation, and 4.0's broader push toward continuous, evidenced processes. Here is a cadence that satisfies all three without heroics.

Continuous: Inline Gates

Detection at ingestion points (logging, ticketing, chat, ETL) runs on every record, every day. This is your preventive control: it keeps the out-of-scope estate clean so periodic sweeps become confirmations rather than cleanups. Alert on every hit — an inline detection firing means an upstream process is emitting account data and needs fixing at the source.

  • Scope entities to CREDIT_CARD_NUMBER, CVV_NUMBER, CREDIT_CARD_EXPIRATION_DATE
  • Mask automatically; never queue raw values for review
  • Feed hit counts to a dashboard as a leak-rate metric

Quarterly: Retention Sweep

Each quarter, sweep the systems permitted to store CHD and reconcile findings against documented retention periods, securely deleting anything past its window (Req 3.2.1). Include a sample-based sweep of adjacent, supposedly-clean systems. Store the scan manifest — systems covered, sample sizes, entity counts, remediations — as the quarter's compliance evidence.

  • Diff against last quarter to spot new leak paths early
  • Treat any SAD finding as an incident, not a ticket
  • Automate via scheduled jobs calling the API in batch

Annual: Scope Confirmation

For the 12.5.2 exercise, run a full-estate discovery pass: every database, file share, log archive, mailbox export, and SaaS data export you can enumerate. Reconcile results against the CDE inventory and dataflow diagrams; every out-of-diagram finding either expands the documented scope or gets remediated and rescanned. Service providers repeat this every six months.

  • Prove the negative for out-of-scope systems with scan evidence
  • Update dataflow diagrams from findings, not memory
  • Hand the QSA the reconciliation, not raw data

API Implementation Examples

Three building blocks: a quick cURL check of a suspect log line, a Python quarterly sweep that walks log files and reports findings with offsets, and a Node.js masking filter for a log shipper. All use the canonical contract documented in the API documentation; get a key on the get-started page.

1. cURL — scan a log excerpt for account data

curl -X POST https://piidetectionapi.com/api/moderate.php \ -H "Content-Type: application/json" \ -d '{ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": "2026-08-25 14:02:11 WARN retry payment for J. Alvarez card=4111111111111111 exp=09/27 cvv=123 gateway_timeout", "entities": ["CREDIT_CARD_NUMBER", "CREDIT_CARD_EXPIRATION_DATE", "CVV_NUMBER", "PERSON_NAME"], "mask_mode": "replace", "threshold": 0.5 }'

The response pinpoints each element with offsets and returns anonymized_text with [CREDIT_CARD_NUMBER], [CVV_NUMBER], and the rest already masked — the CVV hit alone should page someone, because that is SAD at rest.

2. Python — quarterly sweep over log archives

import requests, pathlib, json, datetime API = "https://piidetectionapi.com/api/moderate.php" PAYMENT_ENTITIES = ["CREDIT_CARD_NUMBER", "CVV_NUMBER", "CREDIT_CARD_EXPIRATION_DATE"] CHUNK = 40_000 # stay under the 50,000-char request limit def scan_chunk(text): r = requests.post(API, json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": text, "entities": PAYMENT_ENTITIES, "threshold": 0.6, }, timeout=30) r.raise_for_status() return r.json()["detected_entities"] findings = [] for path in pathlib.Path("/var/log/archive").rglob("*.log"): text = path.read_text(errors="ignore") for off in range(0, len(text), CHUNK): for e in scan_chunk(text[off:off + CHUNK]): findings.append({ "file": str(path), "type": e["type"], "start": off + e["start"], # absolute offset "confidence": e["confidence"], # never persist e["text"] — the finding IS the leak }) report = { "scan_date": datetime.date.today().isoformat(), "files_scanned": len(list(pathlib.Path("/var/log/archive").rglob("*.log"))), "sad_findings": [f for f in findings if f["type"] == "CVV_NUMBER"], "chd_findings": [f for f in findings if f["type"] != "CVV_NUMBER"], } print(json.dumps(report, indent=2))

3. JavaScript (Node) — masking filter inside a log shipper

// Drop-in transform for a log pipeline (e.g. a Logstash/Fluentd sidecar) async function maskAccountData(line) { const res = await fetch("https://piidetectionapi.com/api/moderate.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: process.env.PII_API_KEY, api_type: "pii_detection", text: line, entities: ["CREDIT_CARD_NUMBER", "CVV_NUMBER", "CREDIT_CARD_EXPIRATION_DATE"], mask_mode: "replace" }) }); const data = await res.json(); if (data.entities_detected > 0) { // Metric + alert: an upstream service is logging account data metrics.increment("pci.log_leak", { types: data.detected_entities.map(e => e.type).join(",") }); } return data.anonymized_text; // safe to index and archive } // Usage in the shipping loop const safeLine = await maskAccountData(rawLine); shipper.emit(safeLine);

For high-volume pipelines, batch lines into single requests up to the 50,000-character limit and scan concurrently; the detection call adds one network hop, and the downstream systems it keeps out of PCI scope repay that many times over. You can validate behavior against your own log samples in the interactive demo before wiring anything up.

Best Practices for Cardholder Data Discovery

Lessons from programs that pass assessments quietly, distilled into three operating rules.

Validate, Don't Just Match

Sixteen consecutive digits are everywhere: order numbers, tracking codes, timestamps, hashes. Pure-regex scanners drown teams in false positives until the reports stop being read. Context-aware detection applies Luhn checks, issuer-range logic, and surrounding-language signals, so a hit means a card number with a stated confidence. Set the threshold higher (0.7+) for automated masking and lower (0.4) for audit sweeps where humans review the borderline cases.

Never Let the Scanner Become a Leak

Discovery output that contains the discovered PANs is itself CHD, and now your findings database is in scope. Persist entity types, offsets, file paths, confidence scores, and masked context — never the matched text. When remediation needs to locate the value, the offsets take you there. For environments where even transient transmission is unacceptable, run the detection engine on-premise; the API contract is identical.

Fix Sources, Not Symptoms

Every inline detection hit names an upstream defect: a logger serializing request bodies, a form that lets customers paste card numbers into free text, an integration echoing gateway payloads. Track hits per source and drive them to zero with engineering fixes — masked leaks are compliant, but absent leaks are cheaper. The leak-rate trend line is also the single most persuasive chart you can show a QSA to demonstrate a working control.

Frequently Asked Questions

Is a truncated or masked PAN still cardholder data?
No. A PAN truncated to first six (or eight) and last four digits, with the middle digits permanently removed, is not cardholder data, and systems holding only truncated PANs can be out of scope. Two cautions: storing the truncated form and a hashed form of the same PAN together can allow reconstruction and keeps the data in scope, and display masking (hiding digits in the UI while storing the full PAN) does not descope anything — the stored value is what counts.
We found CVVs in old support tickets. Encrypt or delete?
Delete. Sensitive authentication data must not be retained after authorization under any protection, so encryption is not a remediation. The correct sequence: securely delete or irreversibly redact the CVV from every copy (including ticket revisions and search indexes), identify and fix the intake path that allowed it, and document the finding, remediation, and process change. Ongoing inline detection on ticket creation prevents recurrence — the CVV is masked before the ticket is ever stored.
How is API-based detection different from a traditional card-data discovery tool?
Traditional discovery tools crawl filesystems and databases with pattern rules on a schedule you configure per host. An API puts the same capability at any point in any data path: inside a log shipper, a webhook, an ETL job, a chatbot, a CI pipeline. That enables the preventive, inline pattern (mask before storage) that crawlers structurally cannot do, and the transformer models add contextual validation that cuts the false-positive rate on ambiguous digit strings. Many teams run both: inline API gates for prevention, periodic sweeps (via the same API in batch) for verification.
How often does PCI DSS require data-discovery scans?
The standard mandates rhythm at three levels: quarterly identification and secure deletion of stored account data exceeding retention (Requirement 3.2.1), scope confirmation at least every twelve months for merchants and every six for service providers (Requirement 12.5.2), plus confirmation after significant infrastructure changes. Quarterly discovery sweeps aligned to the 3.2.1 cycle, with an annual full-estate pass for scoping, is the cadence most QSAs consider defensible — and continuous inline scanning makes each of those exercises a confirmation rather than an excavation.
Does scanning data through the cloud API put the API in my PCI scope?
If you transmit live PANs to any external service, that service becomes a third-party service provider in your dataflow and should be assessed as such — our platform operates under strict, audited security controls and TLS-encrypted transport for exactly this reason. Organizations that prefer to keep even the scanning step internal deploy the detection engine on-premise or in their private cloud, where identical request/response contracts mean the integration code does not change. For inline masking of data that should never have contained PANs, the risk calculus favors scanning: the alternative is unmasked PANs propagating through systems with no controls at all.
Can detection help with bank account numbers and other non-card financial data?
Yes. ACH account and routing numbers, IBANs, and SWIFT/BIC codes are outside PCI DSS but firmly inside GDPR, CCPA/CPRA, GLBA, and NACHA data-security expectations. The API detects FINANCIAL_ACCOUNT_NUMBER, ROUTING_NUMBER, IBAN_CODE, and SWIFT_BIC alongside the card entities, so one scanning pipeline covers the whole payments surface. See the how-to guide on detecting bank accounts and IBANs for patterns specific to those formats.

Find Every Stray PAN Before Your Assessor Does

Scan logs, tickets, and databases for cardholder data with one API call — and mask it before it ever lands. Test it on a sample log line right now.

Try the Live Demo View Pricing