Financial Compliance
How a bank uses AI for sanctions screening and AML checks without exposing customer financial identifiers to the language model
How a bank uses AI for sanctions screening and AML checks without exposing customer financial identifiers to the language model.
Note: This scenario relies on detecting sender/recipient names. Person and company detection requires the Python NER sidecar (
GUARDAI_DETECTOR_URL, withdetector.mode: bothoradvanced); in builtin-only mode names are not detected (IBAN, BIC, and national/tax IDs still are, via regex). Setdetection.required_for: [person]in the policy to fail closed if the sidecar is down. See Detector Capabilities.
The Situation
A mid-size European bank processes 1,500 wire transfer requests per day. Each request contains the sender's name, IBAN, recipient IBAN, BIC/SWIFT code, and sometimes a national ID or tax number in the payment reference. The compliance team wants to use AI to pre-screen transfers against sanctions lists and flag suspicious patterns, reducing manual review from 45 minutes to under 5 minutes per case.
The regulator's position is clear: customer financial identifiers (IBANs, account numbers, national IDs) must not leave the bank's infrastructure to reach a third-party AI provider. The bank's information security team adds a further constraint: even internal AI models running in the bank's cloud must not receive raw IBANs in logs or training data.
The Solution
OGuardAI sits between the bank's transfer processing system and the compliance AI model. Financial identifiers are tokenized before reaching the model. The model receives enough context to make compliance decisions (country codes, transfer amounts, payment purpose) without seeing raw account numbers.
Step-by-Step: A Wire Transfer Review
A customer submits a wire transfer to a recipient in a high-risk jurisdiction.
Step 1: Transfer Request Arrives
Sender: Hans Mueller
Sender IBAN: DE89 3704 0044 0532 0130 00
Recipient: Dmitri Volkov
Recipient IBAN: RU02 0445 2080 0000 0640 2357
BIC: SABRRUMM
Amount: EUR 48,500.00
Reference: Invoice INV-2026-0891, Tax ID 7712345678
Purpose: Consulting services Q1 2026Step 2: OGuardAI Transforms the Request
curl -X POST http://localhost:3000/v1/transform \
-H "Content-Type: application/json" \
-H "X-API-Key: $GUARDAI_API_KEY" \
-d '{
"input": "Sender: Hans Mueller\nSender IBAN: DE89 3704 0044 0532 0130 00\nRecipient: Dmitri Volkov\nRecipient IBAN: RU02 0445 2080 0000 0640 2357\nBIC: SABRRUMM\nAmount: EUR 48,500.00\nReference: Invoice INV-2026-0891, Tax ID 7712345678\nPurpose: Consulting services Q1 2026",
"policy": "financial-compliance"
}'Detected entities:
| Original Value | Entity Type | Token | Metadata |
|---|---|---|---|
| Hans Mueller | person | {{person:p_001:083e771529f3}} | role: sender, country: DE |
| DE89 3704 0044 0532 0130 00 | iban | {{iban:ib_001:2f9c04d1be67}} | country: DE, bank: Commerzbank |
| Dmitri Volkov | person | {{person:p_002:6a5b83e0d94c}} | role: recipient, country: RU |
| RU02 0445 2080 0000 0640 2357 | iban | {{iban:ib_002:91d3f7a2c05e}} | country: RU |
| SABRRUMM | bic* | {{custom:bic:x_001:3e8f60b2d7a1}} | country: RU |
| 7712345678 | tax_id* | {{custom:tax_id:x_002:b47a1c92e05d}} | country: RU |
Entity types marked with * are custom types defined via policy rules, not built-in. See the Extending Entities guide.
The safe text sent to the AI:
Sender: `{{person:p_001:083e771529f3}}`
Sender IBAN: `{{iban:ib_001:2f9c04d1be67}}`
Recipient: `{{person:p_002:6a5b83e0d94c}}`
Recipient IBAN: `{{iban:ib_002:91d3f7a2c05e}}`
BIC: `{{custom:bic:x_001:3e8f60b2d7a1}}`
Amount: EUR 48,500.00
Reference: Invoice INV-2026-0891, Tax ID `{{custom:tax_id:x_002:b47a1c92e05d}}`
Purpose: Consulting services Q1 2026The invoice number and purpose pass through: no detector matches them. The transfer amount is a detected money entity, so it stays raw here only because the policy whitelists it (see the whitelist block below): compliance analysis needs the exact figure to apply reporting thresholds. Without the whitelist entry the amount would be tokenized like every other detected value. The entity metadata tells the model that the recipient is in Russia (high-risk jurisdiction) and the sender is in Germany.
Step 3: AI Performs Compliance Analysis
The model receives the tokenized transfer with entity context and generates:
COMPLIANCE SCREENING REPORT
Transfer: `{{person:p_001:083e771529f3}}` (DE) -> `{{person:p_002:6a5b83e0d94c}}` (RU)
Amount: EUR 48,500.00
Risk Flags:
1. HIGH - Recipient jurisdiction (RU) is on enhanced due diligence list
2. MEDIUM - Amount exceeds EUR 15,000 threshold for enhanced monitoring
3. LOW - Payment reference contains tax identifier from high-risk jurisdiction
Sanctions Check:
- `{{person:p_001:083e771529f3}}`: No match found in OFAC/EU sanctions lists
- `{{person:p_002:6a5b83e0d94c}}`: No exact match. Partial name similarity to sanctioned
entity "D. Volkov" (SDN List ref. 29847): requires manual verification.
Recommendation: HOLD for manual review. Escalate to Level 2 compliance
officer for recipient identity verification before processing.
Required Actions:
- Verify recipient identity against passport/ID documentation
- Confirm business relationship (consulting agreement on file?)
- Document enhanced due diligence findingsThe AI made a meaningful compliance decision using country metadata and risk patterns, without ever seeing the actual IBANs or tax ID.
Step 4: Restore for Different Channels
Internal compliance system, full restore:
curl -X POST http://localhost:3000/v1/rehydrate \
-H "Content-Type: application/json" \
-H "X-API-Key: $GUARDAI_API_KEY" \
-d '{
"output": "<compliance report with tokens>",
"session_state": "<encrypted-blob>",
"output_channel": "internal_summary"
}'The compliance officer sees the full report with all IBANs and names restored for the manual review step.
Audit log, masked restore:
curl -X POST http://localhost:3000/v1/rehydrate \
-H "Content-Type: application/json" \
-H "X-API-Key: $GUARDAI_API_KEY" \
-d '{
"output": "<compliance report with tokens>",
"session_state": "<encrypted-blob>",
"output_channel": "log_safe"
}'The audit log records the screening decision, risk flags, and recommendation, with IBANs masked to their first and last character (use a reveal_last_n restore strategy for a last-four display) and names replaced with anonymized identifiers.
Policy Configuration
name: financial-compliance
version: "1.0"
rules:
- entity_type: "person"
protection_level: 2
action: "tokenize"
restore_mode: "full"
- entity_type: "iban"
protection_level: 1
action: "tokenize"
restore_mode: "masked"
- entity_type: "bic"
protection_level: 2
action: "tokenize"
restore_mode: "masked"
- entity_type: "tax_id"
protection_level: 2
action: "tokenize"
restore_mode: "none"
- entity_type: "ssn"
protection_level: 1
action: "redact"
- entity_type: "passport"
protection_level: 1
action: "redact"
# bic and tax_id are bank-defined custom types. They must be declared in
# custom_patterns below before any rule or channel references them, otherwise the
# policy loader aborts startup with "references unknown entity type".
custom_patterns:
- entity_type: "bic"
pattern: '(?i)\b(?:bic|swift)[ \t:#.-]{0,4}([A-Z]{6}[A-Z0-9]{2}(?:[A-Z0-9]{3})?)\b'
confidence: 0.9
value_group: 1
context_words: ["bic", "swift"]
- entity_type: "tax_id"
pattern: '(?i)\b(?:tax id|tax-id|steuer-?id)[ \t:#.-]{0,4}(\d{9,11})\b'
confidence: 0.9
value_group: 1
context_words: ["tax", "steuer"]
defaults:
protection_level: 2
action: "tokenize"
restore_mode: "masked"
# The transfer amount is a detected money entity. Whitelisting the literal value
# is the only path that keeps a detected value raw across the boundary (an
# authored action: allow is rejected at load), so the model can apply reporting
# thresholds to the exact figure.
whitelist:
- "EUR 48,500.00"
metadata_policy:
expose_gender: true
expose_formality: true
expose_language: true
expose_role: true
channel_rules:
internal_summary:
person: full
iban: full
bic: full
tax_id: full
log_safe:
person: abstract
iban: masked
bic: masked
tax_id: none
customer_email:
person: full
iban: masked
bic: none
tax_id: noneWhat OGuardAI Made Possible
Regulatory compliance without crippling AI. IBANs and tax identifiers never leave the bank's trust boundary. The AI receives country-level metadata, enough to flag jurisdiction risk and check sanctions patterns.
Separation of screening and identity. The AI evaluates risk patterns (high-risk country, amount thresholds, name similarity) without accessing the actual financial identifiers. This satisfies both the regulator and the bank's infosec policy.
Channel-specific access control. Compliance officers see everything for manual review. Audit logs keep masked versions for regulatory record-keeping. Customer notifications reveal only what the customer should see.
Redacted entity types. SSN and passport numbers in payment references are redacted entirely (replaced with [REDACTED:type] and purged): they never reach the model, not even as tokens. The policy enforces this at the engine level.
Healthcare Intake
How a clinic uses an AI medical assistant to process patient intake forms with patient identifiers tokenized before the language model sees them
RAG Document Pipeline
How a company safely ingests internal documents into a RAG system so the vector store and LLM never see employee or customer PII