OGuardAI
Use Cases

Finance & PCI-DSS

Protect financial PII when using AI for fraud detection, customer support, and financial reporting with PCI-DSS-aligned controls without limiting AI capabilities

Protect financial PII, credit card numbers, IBANs, SSNs, and account identifiers, when using AI for fraud detection, customer support, and financial reporting.


The Problem

Financial institutions process vast quantities of sensitive data: credit card numbers, bank account identifiers, Social Security numbers, tax IDs, and transaction details. AI can transform fraud detection, customer service, and regulatory reporting, but every AI interaction creates a data exposure risk.

PCI-DSS requires that cardholder data is protected wherever it is stored, processed, or transmitted. Sending a raw primary account number (PAN) to a third-party LLM provider can expand your cardholder-data environment (CDE) and create obligations under PCI-DSS. Whether it actually violates Requirement 3 (protect stored account data) or Requirement 4 (strong cryptography during transmission over open, public networks) depends on storage, transport security, the provider's scope, and your assessed architecture. Note that a generic account identifier is not automatically cardholder data. Financial regulators in the EU, US, and Asia impose additional constraints on where customer financial data may be processed.

Naive approaches fail. Stripping all numbers from transaction data makes fraud detection impossible, the AI cannot analyze patterns without transaction metadata. Replacing account numbers with generic placeholders like [ACCOUNT] loses the ability to distinguish between sender and recipient accounts in multi-party transactions.


How OGuardAI Solves It

OGuardAI intercepts financial data before it reaches the AI model. Each detected sensitive value is replaced with a semantic token that carries its entity type, a stable per-session ID, and a capability flag, and that same token is reused everywhere the value recurs so the model can still tell two accounts or two parties apart. The raw account numbers and cardholder data for those detected entities are removed. Non-sensitive surrounding text (the wording of the alert, dates, references) stays intact, and optional metadata such as a transaction role, formality, language, or gender travels with a token only when the policy deliberately exposes it (expose_role, expose_language, and so on). Country codes and institution identifiers are not derived or attached automatically. The AI model receives enough structure to perform fraud analysis, generate compliance reports, and draft customer communications without seeing the raw financial PII that the detectors flag. The protection covers detected, non-whitelisted entities: a value that no configured detector matches (for example a PAN that fails the Luhn check) or one you deliberately add to the policy whitelist follows the raw path by design, so detector coverage and your whitelist are themselves part of the control surface.

Banking / Fintech Application
    |
    v
OGuardAI Runtime (financial PII exists only here, transiently)
    |
    +---> Tokenized data (no raw PII) ---> LLM Provider
    +---> Encrypted session blob --------> Your Application
    |
    v
Restored output (channel-specific)
    +---> Compliance team: full restore
    +---> Customer notification: masked accounts
    +---> Audit trail: abstract identifiers

Detected Entity Types

Entity TypeExamplesDefault Action
credit_cardVisa, Mastercard, Amex numbersRedact (never reaches the model)
ibanInternational bank account numbersRedact (never reaches the model)
ssnSocial Security numbersRedact
customer_idInternal customer identifiersTokenize
personAccount holder namesTokenize (gender/formality/language metadata where policy exposes it)
bic*SWIFT/BIC codesTokenize
tax_id*Tax identification numbersTokenize
account_number*Domestic account numbersTokenize

Entity types marked with * are custom types defined via policy rules, not built-in. See the Extending Entities guide for how to add custom types.

The person entity type is detected by the NER detector sidecar, which requires detector.mode set to both or advanced. The built-in detector alone covers structured PII (email, phone, IBAN, card, identifiers, address, date of birth) but does not detect person, company, or location names.


Example Policy

The policy below (finance-pci) is an illustrative example you write and drop into your policy directory, not a file that ships in policies/. OGuardAI ships a ready-made financial policy named financial (policies/financial/policy.yaml) that redacts iban, credit_card, ssn, passport, and health_id, tokenizes names and identifiers, and adds bank_account and routing_number as custom_patterns. Use "policy": "financial" for the shipped one, or save the example below as finance-pci.yaml first.

Because bic, tax_id, and account_number are not built-in entity types, this example declares them under custom_patterns before the rules reference them. A policy that references a bare custom label with no matching custom_pattern fails to load at startup.

name: finance-pci
version: "1.0"
description: "PCI-DSS-aligned financial PII protection for AI workflows"

rules:
  - entity_type: "credit_card"
    protection_level: 1
    action: "redact"
    conditions: []

  - entity_type: "ssn"
    protection_level: 1
    action: "redact"
    conditions: []

  - entity_type: "iban"
    protection_level: 1
    action: "redact"
    conditions: []

  # Base restore_mode is set to "full" on the tokenized identifiers because a
  # channel_rule override can only TIGHTEN, never widen: it cannot lift an entity
  # above its stamped base. To let the internal_summary channel restore these to
  # full, the base must already be "full"; the customer_email and log_safe channels
  # below then tighten it down. Where full restoration must be authorization-gated,
  # add auth-bound caller_role / caller_purpose conditions rather than relying on the
  # channel name alone.
  - entity_type: "bic"
    protection_level: 2
    action: "tokenize"
    restore_mode: "full"
    conditions: []

  - entity_type: "person"
    protection_level: 2
    action: "tokenize"
    restore_mode: "full"
    conditions: []

  - entity_type: "customer_id"
    protection_level: 2
    action: "tokenize"
    restore_mode: "full"
    conditions: []

  - entity_type: "tax_id"
    protection_level: 2
    action: "tokenize"
    restore_mode: "full"
    conditions: []

  - entity_type: "account_number"
    protection_level: 2
    action: "tokenize"
    restore_mode: "full"
    conditions: []

# bic, tax_id, and account_number are firm-defined types. Each must be declared
# here before a rule or channel_rule references it, or the policy fails to load.
custom_patterns:
  - entity_type: "bic"
    pattern: '\b[A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?\b'
    confidence: 0.85
    context_words: ["swift", "bic", "wire", "beneficiary"]
  - entity_type: "tax_id"
    pattern: '\b\d{2}-\d{7}\b'
    confidence: 0.85
    context_words: ["tax", "ein", "vat", "tin"]
  - entity_type: "account_number"
    pattern: '(?i)\b(?:account|acct|konto)[ \t:#.-]{0,4}(\d{8,17})\b'
    confidence: 0.9
    value_group: 1
    context_words: ["account", "acct", "konto"]

defaults:
  protection_level: 2
  action: "tokenize"
  restore_mode: "masked"

metadata_policy:
  expose_gender: true
  expose_formality: true
  expose_language: true
  expose_role: false

# Channel overrides only tighten against the stamped base above. internal_summary
# keeps the base "full" for the tokenized identifiers; customer_email and log_safe
# tighten it down. Listing "full" here never widens an entity whose base is lower.
channel_rules:
  internal_summary:
    person: "full"
    bic: "full"
    customer_id: "full"
    tax_id: "full"
    account_number: "full"
  customer_email:
    person: "full"
    bic: "none"
    customer_id: "masked"
    tax_id: "none"
    account_number: "masked"
  log_safe:
    person: "abstract"
    bic: "masked"
    customer_id: "none"
    tax_id: "none"
    account_number: "none"

Note that credit_card, ssn, and iban use action: redact. Redacted values are replaced with [REDACTED:type] and purged from the session, they never reach the AI model, not even as tokens. This removes the PAN from the AI path and can support PCI-DSS Requirements 3 and 4 when combined with properly configured TLS and your organization's broader assessed controls. It is one risk-reduction control, not by itself full satisfaction of any requirement. To hard-fail the request instead of redacting, add on_redact: reject to those rules.

Showing the last 4 digits

Redacting the card outright is the safest default. When a workflow must display the last 4 digits, for example a customer notification that reads "card ending 6467", tokenize the card instead of redacting it and add a restore_strategies block. The full PAN is still never sent to the model: it only ever sees the {{credit_card:...}} token, and only the rehydrate step reveals the last 4.

rules:
  - entity_type: "credit_card"
    protection_level: 1
    action: "tokenize"       # tokenize, not redact, so a partial restore is possible
    restore_mode: "partial"

restore_strategies:
  credit_card: { kind: reveal_last_n, n: 4 }   # mask all but the last 4 characters

Rehydrating 4539 1488 0343 6467 under this policy yields **** **** **** 6467, and the full number is never reconstructed (reveal_last_n fails closed for any value of n characters or fewer). Pair it with a channel_rules override so only the customer-notification channel restores the last 4 while internal logs stay fully masked. The same restore_strategies mechanism expresses salary bands and other coarse ranges with kind: bucket.


Example API Call

Transform a fraud alert

curl -X POST http://localhost:3000/v1/transform \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key-here" \
  -d '{
    "input": "Fraud alert: Customer James Whitfield (ID: CUST-88421) reported unauthorized transactions on card 4539-1488-0343-6467. Three charges totaling EUR 12,450 from merchant accounts in Romania and Cyprus. Customer IBAN: GB82 WEST 1234 5698 7654 32. Contact: james.whitfield@bankmail.com.",
    "policy": "finance-pci",
    "detectors": ["builtin_regex", "python_ner"]
  }'

The person and location entities (James Whitfield, Romania, Cyprus) are only detected when the NER sidecar runs, so the request selects both detectors (builtin_and_ner mode). The card number 4539-1488-0343-6467 is a documented valid-Luhn test PAN; the built-in card detector rejects any candidate that fails the Luhn check, so an invalid number would not be detected or redacted at all.

Response (tokenized)

{
  "safe_text": "Fraud alert: Customer {{person:p_001:ad4f97591c16}} (ID: {{customer_id:cid_001:d00188a0c40c}}) reported unauthorized transactions on card [REDACTED:credit_card]. Three charges totaling {{custom:money:x_001:7b3e02a15c9d}} from merchant accounts in {{location:loc_001:4c1af8820b6e}} and {{location:loc_002:e5d7c93a1f40}}. Customer IBAN: [REDACTED:iban]. Contact: {{email:e_001:1bcaef1a4aff}}.",
  "session_id": "01916b4f-3a1c-7000-8000-000000000002",
  "session_state": "eyJ2IjoxLCJzaWQiOi...",
  "detector_mode": "builtin_and_ner",
  "entity_context": [
    { "token": "{{person:p_001:ad4f97591c16}}", "type": "person" }
  ],
  "entities": [
    { "token": "{{person:p_001:ad4f97591c16}}", "type": "person", "protection_level": "2", "action_applied": "tokenize", "detector": "builtin_and_ner" },
    { "token": "{{customer_id:cid_001:d00188a0c40c}}", "type": "customer_id", "protection_level": "2", "action_applied": "tokenize", "detector": "builtin_and_ner" },
    { "token": "{{custom:money:x_001:7b3e02a15c9d}}", "type": { "custom": "money" }, "protection_level": "2", "action_applied": "tokenize", "detector": "builtin_and_ner" },
    { "token": "{{location:loc_001:4c1af8820b6e}}", "type": "location", "protection_level": "2", "action_applied": "tokenize", "detector": "builtin_and_ner" },
    { "token": "{{location:loc_002:e5d7c93a1f40}}", "type": "location", "protection_level": "2", "action_applied": "tokenize", "detector": "builtin_and_ner" },
    { "token": "{{email:e_001:1bcaef1a4aff}}", "type": "email", "protection_level": "2", "action_applied": "tokenize", "detector": "builtin_and_ner" }
  ],
  "stats": {
    "entities_detected": 8,
    "entities_transformed": 6,
    "entities_blocked": 2
  }
}

The entities array is always present in a transform response; the token IDs, capability hashes, and session_state above are illustrative. The response and its counts are themselves illustrative: the person and the two locations are only produced if the NER sidecar returns them, which depends on the configured model rather than on any fixed rule (the example policy does not pin them with detection.required_for). Assuming the sidecar returns those three spans, finance-pci flags eight entities in this input: the person, the customer ID, the card, the money amount (EUR 12,450, matched by the built-in money detector), the two merchant locations, the IBAN, and the email. Six are tokenized and two (credit_card, iban) are redacted, so they appear as [REDACTED:credit_card] and [REDACTED:iban] in the safe text, are purged from the session, and are counted in entities_blocked. The money amount and the two locations fall under the policy defaults (tokenize), so the model sees stable tokens for them rather than the raw values. Note the built-in money type serializes as custom:money in the token and as { "custom": "money" } in the type field.

The AI model can still analyze the fraud pattern from structure: two distinct location tokens (so it can tell the two foreign merchant accounts apart), a distinct customer, a person, and a single amount token that recurs consistently. It does not see the raw country names, the amount, the IBAN, or the card. The runtime treats every destination as untrusted, so raw values never cross the trust boundary for a tokenized entity: an allow action is deliberately clamped down to tokenize. If a workflow needs the model to reason on specific literal values (for example a known safe country name), the only sanctioned raw path is to add those exact values to the policy whitelist, subject to destination permissions. The whitelist matches an exact normalized literal value regardless of entity type or cardinality, so in principle an amount could be whitelisted by adding its exact literal. In practice each whitelist entry only ever matches that one literal, which suits low-cardinality safe constants such as a country or institution name; open-ended values like amounts keep flowing through as tokens unless every exact value is listed, so they stay tokenized by default.

Rehydrate for the compliance team

curl -X POST http://localhost:3000/v1/rehydrate \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key-here" \
  -d '{
    "output": "<LLM-generated fraud analysis with tokens>",
    "session_state": "eyJ2IjoxLCJzaWQiOi...",
    "output_channel": "internal_summary"
  }'

On the internal_summary channel the compliance team sees the identifiers that the policy stamped with a base restore_mode: "full" (person, customer ID, tax ID, account number, BIC) restored in full. This only works because those rules set the base to full; a channel rule cannot lift an entity above its stamped base. The redacted credit card and IBAN remain [REDACTED:credit_card] and [REDACTED:iban] even for internal users: by policy, redacted entities are purged and never recoverable. Entities left on the masked default (the money amount and locations) restore to their base ceiling on that channel, not to full. Where full restoration must be gated on who is calling, add auth-bound caller_role or caller_purpose conditions rather than relying on the channel name.


PCI-DSS Compliance Notes

These are contributing controls, not evidence of compliance. Whether a given requirement is met depends on your full cardholder-data environment and is determined by your assessment, commonly by a QSA.

PCI-DSS RequirementHow OGuardAI Can Contribute
Req 3: Protect stored account dataCredit card numbers are blocked at the policy level -- they are never tokenized, never stored in session state, never transmitted, which reduces PAN storage in the AI path
Req 4: Strong cryptography in transitSession state containing token mappings is AES-256-GCM encrypted, and no cardholder data is transmitted to the LLM provider; securing every transport hop with TLS over public networks remains the deployment's responsibility
Req 7: Restrict access by need-to-knowChannel rules select per-entity restore ceilings; authorization-sensitive restoration additionally uses auth-bound caller_role / caller_purpose conditions rather than the caller-selected channel name alone
Req 10: Track and monitor accessStructured audit events log every transform/rehydrate operation with entity types and policy applied, never raw values
Req 12: Maintain security policyPolicy YAML files are version-controlled and validated; policy changes are auditable

Additional Regulatory Considerations

These frameworks change over time (for example, EBA guidance now sits in the DORA context), and none of them recognize tokenization as a compliance safe harbor. The controls below may contribute to data-protection and access-control objectives, but your organization must map them to the current framework version and validate applicability with compliance counsel.

  • EBA Guidelines on ICT and security risk management (EU): OGuardAI's trust boundary model keeps raw financial values inside the runtime rather than sending them to a third-party AI, which can contribute to data-protection and outsourcing-risk objectives. It does not by itself establish the broad governance and risk-management program these guidelines require.
  • FFIEC Guidance (US): The sealed session model with automatic expiry can support data-minimization and access-control objectives, one input to an FFIEC-aligned control set, not a demonstration of conformance on its own.
  • MAS TRM (Singapore): Tokenization with optional metadata preservation can contribute to data-protection objectives for outsourced AI processing; applicability must be assessed against the current MAS TRM guidelines.

OGuardAI is one component of a broader compliance program. It addresses the specific risk of cardholder and financial-data exposure during AI interactions. Consult your QSA and compliance team for your complete compliance posture.