LLM PII Redaction: Scrubbing Data Before It Reaches the Model
LLM PII redaction fails in two expensive ways. A weak filter lets names, account details, or health information reach the model. An aggressive filter removes order numbers, URLs, and domain terms that the workflow needs, so the result becomes useless. The fix is not one giant regular expression. Put a typed privacy gateway before every model call, decide which fields the task needs, replace protected values with stable tokens, and keep the restoration map outside the prompt. Then scan the output and test both privacy and task quality. This guide gives AI and backend engineers an implementation sequence, decision rules, a concrete example, and release checks.
Why PII filters fail in real workflows
Personal data rarely stays in one clean field. A support request may contain a customer name in the sender record, an email address in the body, an account number in a screenshot transcript, and a delivery address copied into an agent note. The same payload can also contain values that look sensitive but are operationally harmless, such as an internal ticket ID.
Detection is therefore a classification problem, not just a pattern-matching problem. A regular expression can identify a credit-card-like sequence, but it cannot reliably decide whether AB-10492 is an account identifier, a product code, or a case number. Entity recognition adds context, but it introduces scores, model behavior, and false positives. Presidio's Analyzer documentation exposes recognizers, context, and confidence scores because detection needs policy and tuning around it.
False positives are not hypothetical. In Presidio issue 1498, users reported that a URL recognizer detected ordinary content inside code snippets. The specific recognizer has since received fixes, but the broader lesson remains: a detector's label is evidence for a policy decision, not permission to delete text blindly.
Removing obvious names does not prove that a record is anonymous. NIST defines de-identification around whether data can still be linked to specific people. The ICO's anonymisation guidance also distinguishes anonymisation from pseudonymisation and treats identification risk as contextual. A token that can be reversed through a lookup table is usually a useful engineering control, but it is not the same claim as irreversible anonymisation.
Put one privacy gateway around model access
Route model-bound content through one service or library instead of scattering redaction calls across prompts, controllers, and background jobs. The gateway should accept a typed request and return a sanitized payload plus a reference to protected restoration state.
Pass these fields in each request:
- the workflow name and version;
- the data-purpose label, such as classification or response drafting;
- the authenticated subject and tenant;
- structured fields plus free text;
- the permitted entity types for this task;
- whether any tokens may be restored after inference.
The gateway produces the sanitized content, detector findings, policy decisions, and a short-lived mapping identifier. It should not return the raw token map to the prompt-building code. That separation limits the chance that a debug log, trace, or later prompt step records both the token and its original value.
This design follows the control direction in OWASP LLM02:2025 Sensitive Information Disclosure, which recommends sanitization before model processing and names tokenization and redaction as mitigation techniques. The architecture below is an implementation recommendation for applying those controls to an internal workflow.
Classify fields by purpose before scanning text
Begin with the input schema. For each field, record four properties:
- whether the model needs the field to perform the task;
- which entity types the field may contain;
- whether replacement must preserve relationships between repeated values;
- whether the output is allowed to restore the original value.
A support-ticket classifier probably does not need the sender's email address. Drop that structured field before running any detector. A response-drafting workflow may need to distinguish the customer from another person mentioned in the ticket, but it does not need either name. Replace them with stable typed tokens such as [PERSON_1] and [PERSON_2]. A shipping-status workflow may need the final four characters of an order identifier for the user-facing response. Keep only that permitted representation.
Purpose-first classification prevents a common mistake: sending every field through a detector and assuming masked output is safe. Data that has no task purpose should never enter the model-bound payload. Detection is reserved for fields that must continue through the workflow.
Keep this policy in version-controlled configuration. Reviewers should be able to see that support_triage.v3 drops customer_email, tokenizes person_name, permits product_name, and never restores health_identifier. A change to that policy deserves the same release process as a prompt or tool-schema change.
Use layered detection and typed tokens
Run cheap deterministic rules first for values your organization controls. Exact customer IDs, internal account prefixes, known secret formats, and values already present in structured fields can be found without a statistical detector. Escape the values before matching, and set minimum lengths so short common strings do not erase unrelated words.
Run entity recognizers next for names, addresses, phone numbers, government identifiers, and other contextual data. Configure recognizers by language and workflow. Do not enable every available entity type globally. A recognizer useful for legal intake may be destructive in source-code support, while URL detection may be unnecessary if URLs are allowed by policy.
Convert accepted findings into typed tokens, not a generic [REDACTED] marker. Stable tokens preserve useful structure. If the same email appears three times, every occurrence should become [EMAIL_1]. Different people need different person tokens. The model can then summarize who said what without seeing the underlying identity.
Store the mapping in an encrypted, tenant-scoped record with a short expiry. Bind access to the workflow run and purpose. Never let the model request arbitrary restoration. Application code may restore only an allowed token into an allowed output field after the model response passes validation.
def prepare_model_input(request, policy):
payload = drop_unneeded_fields(request.payload, policy)
findings = deterministic_scan(payload, policy.exact_rules)
findings += entity_scan(payload, policy.enabled_entities)
accepted = apply_thresholds_and_exceptions(findings, policy)
sanitized, token_map = replace_with_typed_tokens(payload, accepted)
mapping_id = token_store.put(
tenant=request.tenant,
workflow=request.workflow,
purpose=request.purpose,
values=token_map,
expires_in=policy.mapping_ttl,
)
return sanitized, mapping_id, audit_summary(accepted)
The pseudocode deliberately leaves model-specific detection behind entity_scan. That makes the policy and token lifecycle testable even if the team changes libraries later.
Apply explicit decision rules
A detector score alone should not decide what leaves your system. Use rules that combine entity type, source field, purpose, and confidence.
Always block known credentials, payment data, health identifiers, and private keys when the workflow has no explicit approved need for them. Do this even when the detector score is low if a deterministic format or source-field label confirms the type.
Tokenize names, email addresses, phone numbers, and postal addresses when the model needs conversational structure but not identity. Preserve one token per distinct value so references remain coherent.
Allow operational identifiers only when the model needs them and the identifier cannot grant access by itself. Prefer partial or synthetic representations. If an order number is required for a drafted reply, application code can insert it after inference rather than exposing it to the model.
Send uncertain findings to a safe path. For a synchronous workflow, that may mean removing the span and asking a human to review the output. For a batch process, quarantine the item with the detector type, score, and surrounding text. Do not silently lower thresholds until the queue disappears.
Policy exceptions should be narrow and testable. An allow rule for example.com inside a URL field is safer than disabling URL detection across every free-text field. The false-positive report in Presidio issue 1498 is a useful regression case for code-heavy input.
Example: sanitize a support ticket
Assume a ticket contains this text:
Maria Lopez cannot access order AB-10492. Reply to [email protected]. Her note says the delivery address is 18 King Street.
The triage model needs the issue type and the fact that an order exists. It does not need the name, email, or street address. The privacy gateway could produce:
[PERSON_1] cannot access order [ORDER_1]. Reply to [EMAIL_1]. The note says the delivery address is [ADDRESS_1].
The classifier returns account_access with a routing label. No restoration is needed. A later response-drafting step can use the same sanitized text. After the draft passes output checks, application code inserts the customer name into a fixed greeting and the order number into a fixed template field. The model never receives the original values.
If the detector labels AB-10492 as a government identifier, the policy should override that interpretation because the source schema marks it as an internal order ID. If the detector misses the email, a deterministic email rule should still catch it. The layers cover different failure modes.
Scan outputs and control restoration
Inspect model output as well. The model may repeat a sensitive value that escaped detection, emit a value from retrieved context, or reproduce a token in a place where restoration is not allowed. Run the same entity scan against the model response, plus exact matching for values in the protected token map.
Treat output findings according to destination. A private operator screen may permit a restored customer name. A Slack channel, analytics event, or vendor ticket should have a stricter policy. The destination is part of the purpose decision.
Restoration should use parsed output, not string replacement over arbitrary prose. Require a structured response with fields such as category, summary, and draft_reply. Allow [ORDER_1] to be restored only in draft_reply, for example. Reject unknown tokens, tokens from another mapping ID, and tokens whose record has expired.
Record counts and entity types in audit logs, but do not log raw findings or token maps. A privacy control that copies every sensitive span into observability storage creates another exposure path.
Test leakage and utility together
A release test set needs labeled sensitive spans and expected task outcomes. Privacy-only tests reward a detector that deletes the whole document. Task-only tests reward a workflow that sends everything to the model. Measure both.
For leakage tests, include obvious formats, names that are also common words, multilingual addresses, identifiers with punctuation changes, copied email threads, OCR errors, and secrets embedded in code. Assert that forbidden raw values do not appear in the sanitized payload, model request logs, output, or traces.
For utility tests, assert that the workflow still routes the ticket correctly, preserves relationships between tokenized people, keeps permitted product names, and returns required structured fields. Track false positives by entity type and source field. A rising false-positive rate after a recognizer update should block release even if leakage tests pass.
Add isolation tests for the mapping store. A run from tenant A must not restore tenant B's token. A later run must not use an expired mapping. A workflow permitted to restore a customer name must still be denied access to a health identifier. These are deterministic authorization tests, not model evaluations.
Before rollout, run the gateway in report-only mode on a bounded sample. Compare detector findings with human labels, add narrow exceptions, and freeze the policy version. Then enable enforcement for one workflow and monitor rejection counts, quarantined items, false positives, and downstream task failures.
Review failures that should block release
Do not call reversible tokenization anonymisation. It reduces exposure and can support data minimization, but a retained mapping changes the privacy claim. Use precise terms from the ICO anonymisation guidance.
Do not keep raw and sanitized payloads side by side in logs. Log the policy version, finding types, counts, decisions, and mapping identifier instead.
Do not use one global confidence threshold. A low-confidence private-key match may deserve blocking, while a medium-confidence person name in a product catalog may need an exception.
Do not restore tokens inside the prompt. Restoration belongs in application code after output validation, with field-level authorization.
Do not judge the gateway by detector recall alone. A privacy filter that breaks the business task will be bypassed under pressure. Leakage and utility are both release gates.
Next action
Choose one model-backed workflow and inventory every field it sends. Mark each field drop, allow, tokenize, or block. Build ten labeled examples from real input shapes, including at least three known false-positive cases. Put the privacy gateway in report-only mode, compare its findings with those labels, and do not enable enforcement until the workflow passes both the no-leakage assertions and its existing task-quality checks.
References
- OWASP LLM02:2025 Sensitive Information Disclosure supports sanitization, tokenization, and redaction before model processing.
- NIST: De-Identification of Personal Information supports the distinction between removing identifiers and preventing linkage to people.
- ICO introduction to anonymisation supports precise use of anonymisation, pseudonymisation, and de-identification terms.
- Presidio Analyzer documentation supports the detector implementation model using recognizers, context, and confidence scores.
- Presidio issue 1498 supports the concrete false-positive risk used in the testing guidance.