Tokenizing PII at ingress in four steps

The pattern runs in four steps, and the order matters.

1. Detect. Before you assemble a prompt, scan the text for sensitive spans. Microsoft Presidio is the de facto open-source tool for this. Its Analyzer pairs spaCy or Hugging Face NER with regex recognizers and context scoring to find names, card numbers, emails, and the rest. 2. Replace. Swap each detected value for a surrogate token. Presidio's Anonymizer ships operators for exactly this (replace, redact, mask, hash, and a reversible encrypt), so a value scrubbed on the way in can be restored on the way out. Community write-ups of agentic design describe this same intercept-and-replace step as the PII tokenization pattern. 3. Build the prompt from tokens. Everything downstream works on tokens rather than plaintext, including the model, the RAG index, the tool calls, and the logs. The plaintext never travels with them. 4. Detokenize on egress, selectively. When an authorized output genuinely needs a real value, resolve the token behind a tightly controlled boundary. Most outputs never need it.

The principle under all four steps is straightforward. A model cannot leak a secret it was never handed. Keep the model away from data worth stealing, and its trustworthiness matters far less.

One honest limit before you get comfortable. The whole scheme is only as strong as step 1, and detection isn't solved. Presidio's own analyzer docs say its recognizers are probabilistic and will miss entities, so anything the detector fails to catch reaches the model in plaintext. Ingress tokenization is bounded by detector recall, full stop. FPE handles structured fields cleanly, but the weak spot is unstructured free text, where detection is least reliable and where most of your real risk lives. So treat detection as the primary risk surface, not a checkbox you tick once. Monitor recall, and allowlist your high-risk fields so the values you can't afford to leak get tokenized by rule, not by a model's best guess.

What tokenization actually does to a sensitive value

Tokenization swaps a sensitive value, a payment PAN or a PII field, for a surrogate that's worthless on its own. You recover the original only by detokenizing against a protected mapping. That's the definition the PCI SSC Tokenization Product Security Guidelines work from, and it sorts tokens into three classes.

  • Irreversible. No path back to the original. Great when you never need the real value again (analytics, joins), useless when you do.
  • Reversible vaulted. The mapping lives in a lookup table or vault. You detokenize by querying it. Easy to reason about, but the vault is a hot target and a read-time dependency you now own.
  • Reversible vaultless. The token is a cipher output computed from the plaintext plus a key. There's no stored table to breach, because the value gets recomputed from the token and the key when you're authorized to see it.

For LLM pipelines, reversible vaultless is usually the sweet spot. You keep restorability without parking a giant honeypot table next to your inference path.

FF1, FF3-1, and why format-preserving encryption fits prompts

The trick that makes vaultless tokenization behave inside a prompt is format-preserving encryption (FPE). A 16-digit number stays 16 digits. An email still looks like an email. That matters because you can drop a token into a prompt or a structured field without tripping length checks, schema validation, or the model's assumptions about what it's staring at.

The standard is NIST SP 800-38G, published March 2016 and updated 4 August 2016. It specifies two AES-based Feistel modes, FF1 and FF3, each taking a non-secret "tweak" that scopes the encryption to a context.

The tweak does double duty, and the second job is the one people miss. Hold it stable and FPE is deterministic: the same plaintext always lands on the same token. That's not a footnote, it's what keeps your pipeline working. Deterministic tokens under a stable tweak mean joins still join, coreference still resolves, and RAG retrieval still finds the right chunk, because a given name becomes the same surrogate everywhere it appears. Vary the tweak per context and you separate domains so a token from one system can't be correlated against another; hold it steady within a context and you preserve referential integrity.

Format-preserving does not mean meaning-preserving, and that's the catch nobody prints on the box. FPE keeps the shape and destroys the semantics, so tokenize a field the model actually has to reason over and you break the reasoning. A tokenized birthdate can't do age math. A tokenized ZIP can't tell the model which region it's in. A tokenized dollar amount can't be compared or summed. Tokenize-everything is not free. The safe targets are identifiers and standalone PII: names, card numbers, emails, account IDs, SSNs. The fields the model must compute on are better left in the clear or generalized (an age bucket instead of a raw DOB) rather than FPE'd into noise the model then reasons over badly.

One more caveat you don't get to skip. After cryptanalysis broke FF3, NIST cut the tweak from 64 to 56 bits and renamed the fixed mode FF3-1. Draft SP 800-38G Revision 1 (out for public comment in 2019) also proposed a minimum domain size of 1,000,000 for FF1 and FF3-1. So use FF1 or FF3-1, never original FF3, and treat a million possible values as the floor before you tokenize a domain. Running FPE over a two-letter US state code is asking for trouble.

Prompt injection and the lethal trifecta

Tokenization matters because the model cannot tell your instructions from an attacker's. The OWASP Top 10 for LLM Applications 2025 (v2.0, announced 17 November 2024) keeps LLM01 Prompt Injection at #1 and LLM02 Sensitive Information Disclosure at #2. The root cause OWASP names is structural: LLMs process instructions and data in the same channel with no reliable separation, so crafted input gets read as a fresh instruction. It comes in two flavors. Direct injection is typed into the prompt; indirect injection hides in a document, web page, or email the model later ingests. OWASP is blunt that neither RAG nor fine-tuning fully fixes it, so you need defense in depth.

Simon Willison sharpened the agent version of this on 16 June 2025 with the lethal trifecta: give an agent (1) access to private data, (2) exposure to untrusted content, and (3) a way to communicate externally, and prompt injection can drive it to exfiltrate data with no exploit code at all. His take on guardrail products that block "95% of attacks" is that 95% is a failing grade, because the attacker just runs at the other 5%.

This is where tokenization earns its place. By removing the private-data leg, it leaves a hijacked agent that only ever sees tokens with nothing worth exfiltrating. You never have to win the impossible fight of sorting every input perfectly into trusted or untrusted, because you have already made the payload worthless.

What this looks like in the wild: Samsung and EchoLeak

Keep two buckets separate: things that actually happened, and things researchers proved could happen.

In the wild. In March 2023, within about 20 days of Samsung Semiconductor lifting its internal ChatGPT ban, three engineers pasted confidential material straight in: source code from a faulty facility-measurement database, code for spotting defective equipment, and a recorded internal meeting they wanted turned into minutes. Samsung banned generative-AI tools on company devices, reported 2 May 2023. (The specific use cases trace back to Korean-press reporting, so treat the details as attributed, not gospel.) This is the canonical case of PII and IP strolling into an LLM, and ingress tokenization is built to catch exactly it.

Proof of concept. In June 2025, Aim Labs disclosed EchoLeak (CVE-2025-32711) in Microsoft 365 Copilot. One crafted email, zero user interaction, could make Copilot reach into OneDrive, SharePoint, Teams, and chat and exfiltrate the contents through an indirect-prompt-injection technique the researchers named "LLM Scope Violation" and rated CVSS 9.3. Microsoft patched it server-side and, by its own account, found no evidence of exploitation in the wild, which keeps it firmly in the research column. It is a clean demonstration of the untrusted-content to private-data to exfiltration chain, and data-plane tokenization blunts the middle link. If the data Copilot could reach were tokenized, the exfiltrated payload would be a bag of surrogates.

PII tokenization best practices before the LLM

If you're building this, here's the short list I'd hold a design to.

  • Tokenize at ingest, before the model boundary. The earlier you replace values, the fewer copies of plaintext survive in logs, caches, and vector stores. Presidio's reversible Encrypt and Decrypt operators give you the restore path. It also matters because, as one tokenization vendor notes, raw PII sent to a third-party API gets logged and retained by the provider, so you want it gone before transmission.
  • Use FF1 or FF3-1, and mind the domain size. Prefer FF1 or FF3-1 over the original FF3, and follow the draft million-value minimum domain proposed in SP 800-38G Revision 1 so you never run FPE over small domains like state codes.
  • Tokenize identifiers, not the fields you need to reason over. FPE preserves format, not meaning, so tokenizing dates, geography, or numeric ranges quietly degrades the model's output. Tokenize standalone PII and identifiers; leave computable fields in the clear or generalize them.
  • Keep the mapping out of the model's reach. The token-to-value store lives in a trust boundary the model and its tools can't touch. If the inference path can query it freely, you have simply rebuilt the vulnerable central store you were trying to avoid.
  • Detokenize sparingly and under authorization. MFA, least privilege, and rate limiting on the resolve path. Most outputs never need real values, so keep plaintext as an exception you explicitly approve.
  • Assume pseudonymized data is still regulated. Under GDPR Recital 26, data you can restore with a separate key is still personal data, and NIST SP 800-122 treats it as PII short of true de-identification. Tokenizing before the LLM shrinks exposure, but it does not delete your obligations on the mapping store, so govern that store with the same care as the data it stands in for.

One honest caveat: this is an engineering threat model, not a full compliance program. Ask your own counsel what "de-identified" means for your data.

How to secure the detokenization path

A detokenization capability is the most dangerous surface in this design. The moment you expose it as a tool an agent can call, it becomes exactly what attackers aim at, so it inherits every control you would put on the tool boundary itself.

If you expose detokenize over the Model Context Protocol, the MCP Security Best Practices aren't optional. The server MUST verify every inbound request and MUST NOT use sessions for authentication. Token passthrough is forbidden: an MCP server must not accept a token that wasn't explicitly issued to it, which is what stops confused-deputy attacks where one service is tricked into acting with another's authority. Add least-privilege scope minimization, per-client consent, non-deterministic session IDs, and SSRF blocking of private and link-local ranges (including the cloud metadata address 169.254.169.254). These are the same MCP data-plane risks recent security surveys keep flagging. A detokenization tool sitting behind anything weaker is a data-exfiltration primitive in disguise. If you're standing up MCP servers, our MCP server security walkthrough goes deeper.

Govern the data plane, not just the model

Most "AI security" money goes to shaping what a model will do: alignment, refusals, output filters. Useful, but it's the wrong plane to bet on alone, because prompt injection keeps winning. The durable move is governing what agents can reach.

That's the idea behind DataShield. Tokenize sensitive fields at ingest so a hijacked agent finds tokens, not raw PII. Authorize each detokenization per tool call, with mid-session revocation so a grant you regret dies immediately instead of at session end. Every call gets sealed into a tamper-evident audit chain you can verify yourself at /verify. The ontology decides which fields count as sensitive, the architecture shows where the trust boundary sits, and /auth is where the per-call authorization lives.

It's the tokenize-on-ingress, detokenize-on-egress pattern with the map parked somewhere the model and its tools can't reach. It lines up with OWASP's LLM02 mitigations (input and output sanitization, least-privilege data access) and it removes the private-data leg of the lethal trifecta. You stop arguing with the model about which inputs to trust, and you make the data itself boring to steal. Want to scope it to your stack? Start a quote.

How to keep sensitive data out of the prompt, plus the MCP-security context.

How to Scrub Sensitive Data Before it Reaches Your LLM video

Scrub sensitive data before it reaches your LLM (Boundary)

Model Context Protocol: MCP Security Risks and Prevention video

MCP security risks and prevention (Giskard)

Prompt Injection, Clearly Explained video

Prompt injection, clearly explained (ByteByteAI)

Frequently asked questions

How do you tokenize PII before it reaches an LLM or AI agent?

Detect sensitive spans at ingress (Microsoft Presidio's Analyzer with NER plus regex is the standard tool), replace each value with a format-preserving surrogate token computed with a keyed FPE mode (NIST FF1 or FF3-1), and build the prompt from tokens. Keep the token-to-value map in a trust boundary the model and its tools can't reach, and detokenize only authorized outputs under MFA and least privilege. One limit to design around: detection is probabilistic, so anything it misses reaches the model in plaintext. Tokenization is bounded by detector recall, which means you monitor recall and allowlist high-risk fields.

Is tokenized or pseudonymized data still considered personal data?

Yes. Under GDPR Recital 26, data whose original can be restored with a separate key remains personal data, and NIST SP 800-122 treats it as PII unless it meets full de-identification standards. Tokenizing before the LLM reduces exposure but doesn't remove your regulatory obligations on the mapping store, so govern that store tightly.

Does tokenization stop prompt injection?

Tokenization leaves the injection itself possible but takes away the payoff. OWASP ranks prompt injection as LLM01 because models process instructions and data in one channel with no reliable separation, and neither RAG nor fine-tuning fully fixes it. Tokenization removes the private-data leg of Simon Willison's lethal trifecta, so a hijacked agent that only ever sees tokens has nothing worth exfiltrating.

Should I use FF1 or FF3 for format-preserving encryption?

Use FF1 or FF3-1, never original FF3. After cryptanalysis, NIST reduced FF3's tweak from 64 to 56 bits and renamed the corrected mode FF3-1. Draft SP 800-38G Revision 1 also proposed a minimum domain size of 1,000,000, so don't apply FPE to small domains like state codes. Keep the tweak stable within a context so tokens are deterministic and your joins, coreference, and RAG retrieval still work.

What controls does a detokenization tool need if I expose it over MCP?

Per the MCP Security Best Practices, the server must verify every inbound request, must not use sessions for authentication, and must not accept token passthrough. Add least-privilege scope minimization, per-client consent to prevent confused-deputy attacks, SSRF blocking of private and link-local ranges including 169.254.169.254, and non-deterministic session IDs.