PCI DSS was written for web checkouts, call centres and point-of-sale terminals. It does not mention language models, and it does not need to: its scope rule is about data, not technology. Any system that stores, processes or transmits cardholder data, or that can affect the security of systems that do, is in scope. An LLM agent that a customer can type a card number into is therefore in scope the moment someone types one, whether or not you designed it to accept card numbers, and so is every log, trace store, vector index, evaluation set and model provider that text flows into.

This article explains how to design a payment-capable LLM application so that the model stays out of scope, what to do when card data reaches it anyway, and which PCI DSS v4.0.1 requirements matter most. It is engineering guidance, not a compliance opinion: your scope and controls are agreed with your Qualified Security Assessor or acquirer, and the standard itself is the authority. For the general machinery of detecting sensitive data, see PII detection and redaction; this page applies it to the one data type with its own industry standard.

Advertisement

Two kinds of card data, two different rules

The most important distinction in PCI DSS, and one that is often blurred, is between cardholder data and sensitive authentication data. They are treated very differently, and the difference drives every design choice in an LLM system.

CategoryElementsMay you store it?
Cardholder data (CHD)Primary account number (PAN); with it, cardholder name, expiration date, service codeYes, if needed and protected: PAN must be unreadable wherever stored (requirement 3.5.1)
Sensitive authentication data (SAD)Full track data, card verification code (CVV2, CVC2 and similar), PIN and PIN blockNo: not retained after authorization, even if encrypted (requirement 3.3.1)

The PAN is what makes the other elements cardholder data; a name and expiry date without a PAN are not. Requirement 3.3.1.2 specifically says the card verification code is not retained after authorization, and the standard allows only issuers with a documented business need an exception. For an LLM application that means a customer typing a CVV into chat creates a problem that encryption cannot fix: if that text lands in a transcript, a log line, an embedding or a fine-tuning dataset, you are storing SAD.

Where card data leaks into an LLM system

Traditional checkouts have one entry point for card data, a form field that you control. Conversational systems have many, and most of them are side effects rather than features.

  • Free-text input. Customers paste card numbers into chat, including in replies to unrelated questions, because chat feels like talking to a person.
  • Voice transcripts. Speech-to-text faithfully writes down a card number read aloud, along with the CVV.
  • Observability. Prompt and response logging, distributed traces and error reports capture the full context window, including earlier turns.
  • Memory and retrieval. Conversation memory and vector stores embed past turns; deleting the source text does not remove what was indexed.
  • Evaluation and training data. Sampled transcripts become test sets and fine-tuning corpora, copying card data into new systems and, for fine-tunes, into model weights where it cannot be deleted at all.
  • The model provider. Every prompt is transmitted to the provider and may be retained for abuse monitoring under their terms.
  • Tool results. A tool that returns a full payment record puts the PAN straight into the context window.

Each of these is a separate system that would join your cardholder data environment. The design goal is to make sure card data never reaches any of them, and to detect and contain it when it does.

Advertisement

Reference architecture: tokens in, tokens out

Keep the model out of the cardholder data environment: tokens in, tokens outCustomerchat, voice or appPAN guardLuhn detect, redact, steerLLM agentsees token + last four onlyPSP hosted fieldscard entered here, not in chatPayment servicetokens only, no detokenizePayment toolscharge(token, amount)PSP / vaultPCI DSS compliant TPSPLogs, traces, evalsscanned: no PAN, no CVVmessagesredactedpay linkcard datatool calltoken, amounttokenOut of scope only if segmented: the agent, its model provider and its logs must not store, process or transmit card dataand must not be able to affect the security of the systems that do. Confirm the boundary with your assessor.
The agent orchestrates payments using tokens and the last four digits. Card entry happens in the payment service provider's hosted fields, and an inbound guard redacts card numbers that customers type anyway.

The pattern is the same one that shrinks scope for web checkouts. Card entry happens in fields hosted by a PCI DSS compliant payment service provider, delivered as a payment link, an iframe in your app or a secure voice flow. The provider returns a token, and your payment service uses it to charge. Whether that service stays in scope depends on whether it can detokenize or affect the payment page; agree it with your assessor. The agent sees only the token, the card brand and the last four digits, which is enough to say "charge the Visa ending 4242?" and not enough to be cardholder data.

Segmentation is what makes the agent out of scope, and segmentation is a claim you prove, not a label you apply. The agent's runtime must not be able to reach card data stores, its credentials must not grant access to the payment service's data, and it must not be able to change the security of in-scope systems. Requirement 12.5.2 asks you to document and confirm scope at least once every twelve months and after significant change; adding an agent to a payment flow is a significant change.

The inbound guard

Even with hosted fields, customers will type card numbers into chat. Put a guard in front of everything: before the model, before logging, before memory. It detects card numbers with a pattern plus the Luhn checksum that card numbers satisfy, which rejects most random digit strings such as order numbers and phone numbers, redacts them, and tells the application to steer the customer to the secure payment link.

import re

CANDIDATE = re.compile(r"(?<!\d)(?:\d[ -]?){12,18}\d(?!\d)")   # 13-19 digits, spaces or dashes

def luhn_ok(digits: str) -> bool:
    total, parity = 0, len(digits) % 2
    for i, ch in enumerate(digits):
        d = int(ch)
        if i % 2 == parity:
            d *= 2
            if d > 9:
                d -= 9
        total += d
    return total % 10 == 0

def redact_pan(text: str) -> tuple[str, int]:
    hits = 0
    def repl(m):
        nonlocal hits
        digits = re.sub(r"\D", "", m.group())
        if 13 <= len(digits) <= 19 and luhn_ok(digits):
            hits += 1
            return "[CARD NUMBER REMOVED]"
        return m.group()
    return CANDIDATE.sub(repl, text), hits

CVV_HINT = re.compile(r"\b(cvv|cvc|cvv2|security code)\b\D{0,15}\d{3,4}\b", re.I)

def guard_inbound(text: str) -> dict:
    clean, pans = redact_pan(text)
    clean, cvvs = CVV_HINT.subn("[SECURITY CODE REMOVED]", clean)
    return {"text": clean, "pan_hits": pans, "cvv_hits": cvvs,
            "steer": pans > 0 or cvvs > 0}      # reply with the secure payment link

Run the guard on raw input before it touches any log; a guard placed after the logging middleware protects nothing. Count hits as a metric without recording the matched text. Detection is imperfect: numbers get split across messages or spelled as words, and some reference numbers pass Luhn by chance. So treat the guard as a containment control on top of an architecture that does not depend on it, and scan stored logs and transcripts on a schedule for anything it missed, as you would for secrets in the context window.

Payment tools that never see a card number

Agents act through tools, and tools are where an LLM payment system can be made safe by construction. Give the agent operations on tokens, enforce limits in code, require confirmation for money movement, and make every charge idempotent so a repeated tool call cannot charge twice.

def charge_saved_card(customer_id: str, payment_method_token: str,
                      amount_minor: int, currency: str, idempotency_key: str) -> dict:
    """Charge a card the customer already saved through the PSP's hosted form.

    The model supplies a token it obtained from list_payment_methods(); it never
    sees or supplies a PAN. Amount limits and confirmation are enforced here,
    not in the prompt.
    """
    method = payments.get_method(customer_id, payment_method_token)
    if method is None:                                  # token must belong to this customer
        return {"status": "error", "code": "UNKNOWN_METHOD"}
    if not 0 < amount_minor <= policy.max_agent_charge(customer_id, currency):
        return {"status": "error", "code": "AMOUNT_NOT_ALLOWED"}
    if not confirmations.approved(customer_id, idempotency_key):
        return {"status": "needs_confirmation",
                "summary": f"Charge {amount_minor} {currency} to card ending {method.last4}"}
    result = psp.charge(token=payment_method_token, amount=amount_minor,
                        currency=currency, idempotency_key=idempotency_key)
    return {"status": result.status, "charge_id": result.id, "last4": method.last4}

Check that the token belongs to the customer in the session, so a prompt-injected token from another account is rejected. Return the last four digits, never the full record. Keep amount limits and confirmation in the tool, where a manipulated model cannot talk its way past them; the tool abuse article covers the wider class of attacks this defends against.

When card data does reach the model

Some products genuinely need the model to handle card data, and some designs fail. Either way, the consequences follow directly from the standard. The model provider, if it receives PANs, is a third-party service provider for your PCI DSS purposes, and requirement 12.8 applies: maintain a list of service providers, a written agreement in which they acknowledge responsibility for the card data they handle, due diligence before engagement, monitoring of their PCI DSS compliance status at least annually, and a clear record of which requirements each party manages. Many model APIs are not offered as PCI DSS validated services; check the provider's attestation of compliance before you send a single PAN.

Everything that stores the transcripts is then in scope too. PAN must be unreadable in storage, including in logs (3.5.1); PAN shown to staff must be masked so that no more than the BIN and last four digits are visible to anyone without a business need (3.4.1); transmission over public networks needs strong cryptography (4.2.1); and audit logs must be retained for at least twelve months with three months immediately available (10.5.1). If a CVV was captured, it must be purged, and you should treat the event as an incident.

Requirements that bite hardest

RequirementWhat it says, brieflyLLM-specific angle
3.3.1, 3.3.1.2No SAD after authorization; no card verification codeTranscripts, memory and eval sets must not hold CVVs
3.4.1Mask PAN on display beyond BIN and last fourAgent replies and support consoles show last four only
3.5.1PAN unreadable wherever storedIncludes logs, traces and vector stores
4.2.1Strong cryptography for PAN over public networksCalls to a model provider that may see PAN
6.4.3, 11.6.1Inventory and authorise payment page scripts; detect tamperingChat widgets embedded on payment pages are scripts
10.5.1Retain audit logs twelve months, three immediately availableAgent tool calls are auditable actions
12.5.2Document and confirm scope annually and on changeAdding an agent is a change; redraw the data flow
12.8Manage third-party service providersModel and observability vendors that see card data

One scope detail for small merchants: in January 2025 the PCI SSC revised SAQ A, effective 31 March 2025, removing requirements 6.4.3 and 11.6.1 for SAQ A merchants and adding eligibility criteria, including that all elements of the payment page come directly from a compliant provider and that the merchant has confirmed its site is not susceptible to script attacks that could affect the e-commerce system. An AI chat widget injected into checkout pages bears directly on that confirmation.

Worked example: a subscription billing assistant

A software company adds an assistant that can explain invoices, update the payment method and retry failed charges. The initial prototype asked customers to type a new card into chat, logged every turn to an observability vendor and sent prompts to a hosted model. That puts the chat service, the vendor, the model provider and the transcript database into scope, and the CVV prompt makes the transcripts a SAD violation.

The redesign: "update payment method" returns a short-lived link to the provider's hosted card form, which posts the card directly to the provider and returns a token to the payment service by webhook. The agent's tools are list_payment_methods, which returns brand, last four and token, and retry_invoice, which takes an invoice id and a token and requires confirmation. The inbound guard runs in the gateway before logging. A weekly job scans transcripts with the same detector and alerts on any hit. The scope document now shows the agent, model provider and observability vendor outside the cardholder data environment, with the segmentation evidence the assessor asked for: network rules, service account permissions, and guard test results.

A note on AI in assessments

In March 2025 the PCI SSC published Integrating Artificial Intelligence in PCI Assessments. It is aimed at assessors who use AI to review evidence or draft reports, keeps the human assessor responsible for findings, and changes no PCI DSS requirement. It is not a guide to building LLM payment applications.

Failure modes

FailureHow it happensControl
CVV in transcriptsPrompt or customer supplies it in chat or voiceNever ask; guard redacts; purge and treat as incident
PAN in logsLogging middleware before the guardGuard at the edge; scheduled scans of stores
PAN in fine-tune dataTranscripts sampled for trainingScan datasets; exclude flagged conversations
Scope creep via memoryVector store embeds raw turnsEmbed only guarded text
Cross-account chargeInjected token or customer idToken ownership check in the tool
Duplicate chargeModel retries a tool callIdempotency keys passed to the provider

Audit every payment tool call with the customer, token, amount, confirmation and result, and keep it tamper-evident, following the audit logging architecture.

What to do next

  1. Draw the data flow for your agent and mark every system that could receive card data, including logs, traces, memory, evals and the model provider.
  2. Move card entry to the provider's hosted fields or secure voice capture, and give the agent tokens and last four digits only.
  3. Deploy an inbound guard with Luhn detection before any logging, and schedule scans of stored transcripts.
  4. Remove any prompt or flow that asks for a CVV, and purge any that has been captured.
  5. Build payment tools that check token ownership, enforce limits, require confirmation and use idempotency keys.
  6. Update your scope document and service provider list, and review the segmentation evidence with your assessor.
Key takeaway: PCI DSS scope follows card data, so an LLM agent is in scope as soon as a card number reaches it, along with its logs, memory, evaluation data and model provider. Keep the model out by moving card entry to provider-hosted fields, giving the agent tokens and last four digits only, guarding every input before logging, and building payment tools that enforce ownership, limits and confirmation. Never let a CVV be stored anywhere.