Sheet A-102
PII Swapping Gateway
Swaps personal data (BVN, NIN, phone, card and email) for random tokens before a prompt leaves for an outside AI model, then puts the real values back in the reply.
- Project
- PII Swapping Gateway
- Role
- Designer and builder
- Status
- In development
- Stack
- Python 3.10+, Zero dependencies, HMAC-SHA256, unittest, Anthropic API (optional)
- Year
- 2026
Part of my Agent Governance Kit, with a tamper-evident ledger and a policy guard. A tested prototype.
Problem
Staff and AI agents send customer data to hosted models. In Nigeria, a prompt carrying a BVN or NIN is a cross-border transfer of personal data under the NDPA 2023, and the provider may keep it.
Who it's for
Nigerian businesses that use hosted AI models with customer data: banks, fintechs and support teams.
My role
Designer and builder. What I built:
- Detects email addresses, Nigerian phone numbers (080… and +234…), card numbers with a Luhn check, 11 digit BVN and NIN, US SSN and IBAN.
- Swaps each for a random token such as [CARD_1ACF18]. The real value stays in a private in-memory vault.
- restore() puts the real values back into the model's reply. leak_check() re-scans outgoing text and blocks the call if anything slipped through. clear() wipes the vault at session end.
- A Trajectory Ledger: an HMAC hash-chained record of prompts, tool calls and results. verify() catches edits, deletions in the middle and reordering; anchoring the head catches deletions at the end.
- A Policy Guard: tools outside the allowlist are refused, limits and approval thresholds are enforced, and every refusal and sign-off lands in the ledger.
Key decisions
Random tokens, not tokens computed from the data.
Why An 11 digit BVN space is small enough to brute force. Compute the token for every possible number and a deterministic token can be reversed.
The ledger records how many items were redacted, never the values.
Why An audit trail that stores the personal data it was meant to protect becomes the next leak.
Over-redact: any 11 digit number is treated as a BVN or NIN.
Why A false positive costs a slightly odd prompt. A false negative sends someone's identity number abroad.
How it works
- 1
Prompt
Written by staff or an agent, with customer details in it.
- 2
Detect
BVN, NIN, phone, card, email, SSN, IBAN.
- 3
Swap
Each value becomes a random token; the real value stays in the vault.
- 4
Leak check
Outgoing text is scanned again; any survivor blocks the call.
- 5
Model
Sees only tokens.
- 6
Restore and wipe
Real values go back into the reply; the vault is cleared.
Results
- automated tests
- 27
- runtime dependencies
- 0
Each figure comes from the project's own data or the owner.
What it doesn't stop
- Pattern detection misses names, addresses and free-text identifiers.
- The vault lives in memory. Production needs encrypted storage with access control and expiry.
- The ledger is a single file with one writer. Production needs write-once storage and regular head anchoring.
- Unrelated 11 digit numbers are redacted too, by design.
Mapped to
- Nigeria Data Protection Act 2023: data minimisation, security of processing, cross-border transfer
- GDPR Art. 5(1)(c) and Art. 25: data minimisation and protection by design
- EU AI Act Art. 10 (data governance), Art. 12 and Art. 19 (record keeping and log retention)
- NIST AI RMF (Govern, Map, Measure, Manage) and ISO/IEC 42001 traceability
What I'd change next
- A named-entity detector (Microsoft Presidio) for names and addresses.
- An encrypted vault with expiry.
- Anchoring the ledger head to a separate system on a schedule.
Stack
- Python 3.10+
- Zero dependencies
- HMAC-SHA256
- unittest
- Anthropic API (optional)