PII Detection in LLM Applications:
Why Regex Isn't Enough
Regex-based PII detection misses up to 40% of personally identifiable information in LLM outputs. Names in narratives, obfuscated contacts, and quasi-identifier combinations all slip through. Here's what a production pipeline needs — and how a governance layer lets you plug in detection at any level.
Why This Matters Now
- 1.LLMs memorize and regurgitate training data — including PII from public datasets.
- 2.Users paste sensitive information into prompts that gets logged and processed.
- 3.GDPR fines for PII mishandling reached €2.1B in 2025. Regulators are watching AI.
- 4.Enterprise buyers require PII controls before deploying AI-powered features.
- 5.A single PII leak in a customer-facing AI response can destroy user trust permanently.
The PII Detection Spectrum
Not all PII is created equal. Some types are easy to detect with patterns. Others require understanding context, combinations, and intent.
Direct Identifiers
Regex: HighRegex works for structured formats (SSN, credit cards). Fails for names in natural language context.
Quasi-Identifiers
Regex: Very LowNot PII in isolation. Becomes identifying when combined. Requires contextual analysis.
Contextual Identifiers
Regex: NoneOnly identifiable in context. No pattern to match. Requires semantic understanding.
Embedded in Narratives
Regex: LowLLMs generate PII in varied formats and contexts. No single extraction pattern works.
Where Regex Fails: Real Examples
These are actual patterns from production LLM outputs where regex-only detection failed.
What a Production PII Pipeline Looks Like
Effective PII detection requires multiple stages, each catching what the previous missed. A governance layer like Overrule provides the framework to orchestrate these stages as pluggable policies.
Normalization
Convert obfuscated patterns to canonical form before scanning
- ✓Expand dot-separated emails (rashid dot khan → rashid.khan)
- ✓Convert spelled-out numbers to digits (five five five → 555)
- ✓Decode character substitutions (@ → at, # → number)
- ✓Normalize unicode homoglyphs and zero-width characters
Pattern Matching
Apply regex for well-structured PII types (first pass)
- ✓SSN, credit cards, phone numbers in standard formats
- ✓Email addresses, URLs with query parameters
- ✓Date of birth patterns, IP addresses
- ✓National ID formats (passport, driver's license patterns)
NER + Context Analysis
Named Entity Recognition to catch names, organizations, locations
- ✓Person name detection in natural language context
- ✓Organization names linked to individuals
- ✓Location data that narrows identity (address fragments)
- ✓Relationship terms that create linkable records
Sensitivity Scoring
Classify detected PII by risk based on context and combination effects
- ✓Single identifier vs quasi-identifier combination scoring
- ✓Context sensitivity (medical, financial, legal, employment)
- ✓Re-identification risk based on population size estimation
- ✓Regulatory classification (GDPR special category, HIPAA PHI, CCPA)
Action Enforcement
Apply the appropriate response based on policy and sensitivity
- ✓Block: reject the response entirely for critical PII leaks
- ✓Redact: replace PII with tokens ([NAME], [EMAIL], [PHONE])
- ✓Flag: log for human review without blocking (low-confidence detections)
- ✓Pass: allow through with audit trail for compliant contexts
How Overrule Fits In
Overrule is the governance layer — it provides the framework for enforcing PII policies, logging violations, and proving compliance. The built-in pii-detection policy catches structured PII (SSNs, credit cards, emails, phone numbers) via pattern matching. For advanced detection (names, quasi-identifiers, contextual PII), you subclass BasePolicy and plug in any NER model or external API:
from overrule import Guard
from overrule.policies import BasePolicy
# Built-in: catches SSN, email, phone, credit cards
async with Guard() as guard:
result = await guard.evaluate(
content="Customer SSN is 123-45-6789",
policies=["pii-detection"],
)
# result.violations → SSN detected, logged to audit trail
# Custom: plug in your own NER model for advanced detection
class AdvancedPiiPolicy(BasePolicy):
"""Bring your own model for names, addresses, context."""
policy_id = "advanced-pii"
async def evaluate(self, content: str) -> list[Violation]:
# Call spaCy, Presidio, AWS Comprehend, or any detector
entities = your_ner_model.detect(content)
return [self.violation(e.text, e.type) for e in entities]
# Same governance framework — enforcement + audit trail
async with Guard(policies=[AdvancedPiiPolicy()]) as guard:
response = await guard.chat(model="gpt-4o", messages=messages)The value isn't in the regex — it's in the enforcement and audit trail. Every detection (built-in or custom) gets logged, monitored, and exportable for regulators. Your detection can be as simple or sophisticated as your use case demands.
Regulatory Compliance Mapping
GDPR (EU)
Articles 5, 25, 32Minimize processing of personal data. Implement data protection by design.
CCPA (California)
Sections 1798.100-199Allow consumers to know what PII is collected. Provide opt-out of sale.
HIPAA (US Healthcare)
45 CFR 164.502Protect PHI. Minimum necessary standard for use and disclosure.
EU AI Act
Articles 13-15High-risk AI must be transparent about data processing and enable oversight.
Start governing PII in your AI responses
Built-in pattern detection for structured PII. Pluggable framework for advanced detection. Every violation logged to an audit trail you can export for regulators.