PII Masking
PII masking scans AI request and response content for personally identifiable information and replaces detected entities according to a configurable masking mode. The detector uses compiled regex patterns for each entity type.
What PII Masking Detects
Section titled “What PII Masking Detects”The masker ships with built-in regex patterns for eight entity types:
| Entity Type | What It Matches | Example |
|---|---|---|
email | Email addresses | [email protected] |
phone | Phone numbers (Chinese mobile format) | 13800138000 |
credit_card | Credit card number patterns (13-16 digits) | 4111-1111-1111-1111 |
id_card | Identity card numbers (17 digits + check) | 110101199001011234 |
url | HTTP and HTTPS URLs | https://internal.example.com |
ip_address | IPv4 addresses | 192.168.1.100 |
person | Person name patterns | Detected via keyword or custom pattern |
address | Physical address patterns | Detected via keyword or custom pattern |
The person and address types are defined in the entity enum but do not have built-in regex patterns. Configure them through customEntities when you need name or address masking.
Masking Modes
Section titled “Masking Modes”The masker supports three replacement modes, each producing different output for detected entities:
| Mode | Replacement | Example (email detected) |
|---|---|---|
| Mask | [entity_type] brackets | [email] |
| Redact | Literal [REDACTED] | [REDACTED] |
| Anonymize | <entity_type> angle brackets | <email> |
Pick the mode that matches your observability and audit requirements. Mask mode preserves the entity type in the replacement, which helps you understand what was removed. Redact mode provides a uniform placeholder with no type information. Anonymize mode uses a distinguishable angle-bracket format.
When masking is disabled (enabled: false), the detector returns the original text unchanged with zero runtime cost.
Configuration
Section titled “Configuration”PII masking is configured inside an AIService resource under the piiMasking field:
apiVersion: gateway.nantian.dev/v1alpha1kind: AIServicemetadata: name: private-gpt4 namespace: nantian-demospec: provider: openai format: openai model: gpt-4o piiMasking: enabled: true mode: maskFor custom entity detection, provide additional regex patterns per entity type:
apiVersion: gateway.nantian.dev/v1alpha1kind: AIServicemetadata: name: private-gpt4-custom namespace: nantian-demospec: provider: openai format: openai model: gpt-4o piiMasking: enabled: true mode: redact customEntities: - entityType: person pattern: "(Mr|Ms|Dr)\\s+[A-Z][a-z]+\\s+[A-Z][a-z]+" - entityType: address pattern: "\\d+\\s+[A-Za-z]+\\s+(Street|Road|Avenue|Lane)"Custom patterns are added alongside the built-in patterns. Both sets run on every message, and overlapping matches are deduplicated with the longest match taking precedence.
Testing and Validation
Section titled “Testing and Validation”Before enabling PII masking in production, test your patterns against sample data:
# Send a test request with known PIIcurl -X POST https://gateway/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o", "messages": [{"role": "user", "content": "My email is [email protected]"}] }'The response should show the masked content. For audit-only validation without affecting end users, temporarily set mode: redact in a staging AIService with production traffic mirrored via Request Mirroring.
Performance
Section titled “Performance”PII masking adds regex scanning to every request and response message. The overhead depends on message size and pattern complexity:
| Scenario | Typical Overhead |
|---|---|
| Short prompts (<500 chars) | <1ms |
| Long prompts (2K-8K chars) | 1-5ms |
| Response streaming | Per-chunk overhead (masking applied to each chunk) |
| Custom regex with backtracking | Potentially higher — test thoroughly |
The built-in patterns are compiled once at startup and use linear-time matching where possible. Custom patterns that include .* or nested quantifiers may trigger backtracking on long inputs — validate with representative data.
How Masking Works
Section titled “How Masking Works”The masker runs detect() to find all entity matches, then replaces them in left-to-right order. Overlapping matches are resolved by keeping the longest match at each position. For example, if a URL contains an embedded IP address, only the URL is replaced, not the IP.
The mask() method returns three values:
- The masked text as a string
- A count of entities replaced
- A list of
(original, replacement)pairs for audit logging
You can use the audit pairs to verify which PII was removed without logging the original sensitive data to your primary log storage.