Input-side defense masks PII before it goes to an external LLM, then restores only the values that need restoring in the answer that comes back.
Why the input is the first line of defense
The moment a request goes to an external LLM API, the text in the body crosses over to the vendor's infrastructure. That text may contain PII (Personally Identifiable Information), such as a member's name or phone number. If it does, PII arrives in plaintext somewhere outside your control.
Masking PII at the input is the earliest line of defense. Exposure removed here also reduces risk on everything downstream: RAG, tool calls and observability logs.
Input-side defense splits into detection and substitution. Detection finds which tokens are PII, and substitution replaces those tokens with fake values before sending them to the LLM.
Separate the two stages so you can tune detection accuracy and substitution naturalness independently.
Microsoft Presidio
Microsoft Presidio is the common choice for detection. Internally it separates AnalyzerEngine (detection) from AnonymizerEngine (substitution).
The detectors combine Named Entity Recognition (NER) based on spaCy, Stanza or Transformers with regular expressions, checksum validation and custom recognizers.
The default entities for English include PERSON, EMAIL_ADDRESS, PHONE_NUMBER, CREDIT_CARD, IP_ADDRESS, LOCATION, US_SSN and DATE_TIME.
On English text it catches a substantial share right after installation. Korean requires separate reinforcement for names, addresses, resident registration numbers and account numbers.
Reinforcing Korean
Use a Korean NER model to find names, place names and organizations, and register Korea-specific identifiers separately with a PatternRecognizer.
- Reinforce PERSON, LOC and ORG with
klue/bert-base-nerorKPF-bert-ner - Cover resident registration numbers, account numbers and business registration numbers with a
PatternRecognizercombining a regular expression and a checksum - Inject a Korean spaCy model (
ko_core_news_lg) or a transformers backend intonlp_engine_provider
Presidio's accuracy depends on the Korean training distribution of the NER model. When the domain changes, as in healthcare, finance or HR, the false negative patterns change with it.
In production, collect the misses into a golden set and review it every quarter.
Reversible anonymization
Detection alone is not enough. If the substituted values remain in the LLM response, the user sees a fake name instead of their own.
LangChain's PresidioReversibleAnonymizer retains the substitution mapping. Once the response comes back, that mapping restores the values that need to be original again.
from langchain_experimental.data_anonymizer import PresidioReversibleAnonymizer
anonymizer = PresidioReversibleAnonymizer(
analyzed_fields=["PERSON", "PHONE_NUMBER", "EMAIL_ADDRESS", "KR_RRN"],
faker_seed=42,
add_default_faker_operators=True,
)
safe_prompt = anonymizer.anonymize("My name is Hong Gildong and my number is 010-1234-5678.")
answer = llm.invoke(safe_prompt)
final = anonymizer.deanonymize(answer)In the code above, anonymize finds the entities registered in analyzed_fields and replaces them with fake values. The substitution mapping is stored in deanonymizer_mapping.
When the LLM response returns, deanonymize consults that mapping and restores the fake values to the originals. KR_RRN is an identifier registered by hand for the Korean resident registration number.
Keep deanonymizer_mapping only in session-scoped or request-scoped memory. Never persist it.
Writing the mapping to disk or a database turns that store into a shadow database. It holds plaintext PII paired one-to-one with the fake values.
Design mapping storage in local memory outside checkpointed state. Naming a type PrivateState does not prevent persistence; inspect the actual checkpointer and traces.
Consistent replacements within a session
Tasks that reference the same entity repeatedly need consistent replacements within a session. This post proposes assigning random substitutes to original identifiers and reusing that session's mapping for later requests.
| Item | Design condition | Limitation |
|---|---|---|
| Same entity | Reuse the substitute within a session | Repetition and relationships can remain visible |
| Different session | Use separate mappings and access boundaries | The mapping store needs protection |
| Restoration | Restore only required fields for an authorized user | Possessing a substitute does not confer access |
| Session end | Discard mappings according to their lifetime | Existing logs and replicas need separate checks |
Substitution does not guarantee cryptographic anonymity or differential privacy. Separate tasks the model can perform without originals from local processing that requires them. Changes to amounts or dates also need tests for altered calculation and retrieval semantics.
Indirect identifiers and context
Removing direct identifiers can leave combinations of workplace, age, role, and medical history that narrow a person's identity. Regex detection alone does not evaluate contextual identifiability.
Additional model or human review needs its own effectiveness evaluation. This post does not claim that a particular small model removes every indirect identifier or provides equivalent protection at lower cost.
| Evaluation item | Outcome to check |
|---|---|
| Direct identifiers | Domain-specific misses and false positives for names, phones, accounts, and similar fields |
| Context combinations | Whether ordinary individual fields become identifying together |
| Task quality | Retained accuracy for retrieval, calculation, and summarization |
| Restoration authority | No return of originals to another session or user |
Input-processing flow
The following design separates detection, consistent substitution, and restoration. Validate each stage on the service's evaluation set.
flowchart TD
A[User input] --> B[PII detection and domain checks]
B --> C[Consistent session replacements]
C --> D[Check remaining context and transmission policy]
D --> E[External LLM]
E --> F[Output checks]
F --> G[Restore authorized fields locally]
This flow proposes reducing what reaches the external model. Later stages do not guarantee detection of every earlier error. Separately check whether mappings and originals enter logs or checkpoints together.
Summary
Separate detection, substitution, and restoration in input processing. Tasks that repeatedly reference an entity need consistent mappings within a session. After removing direct identifiers, evaluate contextual exposure and task quality together. Limit restoration according to user authorization, not merely the presence of a mapping.
The next post covers defenses at the RAG, tool, and MCP stages.