PII Sanitization
PII sanitization is data minimization for your records: detect sensitive data and redact it before a decision is recorded or stored.
sanitize For: governance & audit
The principle is minimize before you store: a record you never wrote sensitive data into is one you never have to scrub later.
Install
pip install briefcase-ai[sanitize]Sanitize before capture
-
Detect — scan the incoming ticket text for known patterns (email, phone, and any custom patterns you register).
-
Redact — replace matches with a
[REDACTED_<TYPE>]marker so the meaning survives but the sensitive value doesn’t. -
Capture — record the decision on the sanitized text, so the stored record never held raw PII.
from briefcase.sanitize import Sanitizer
sanitizer = Sanitizer()result = sanitizer.sanitize("Email me at jane.doe@example.com please")
print(result.sanitized) # Email me at [REDACTED_EMAIL] pleaseprint(result.redaction_count) # 1print(result.has_redactions) # True
# feed result.sanitized into classify_ticket() so the captured record is cleansanitize() returns a SanitizationResult with .sanitized, .redactions, .redaction_count, and .has_redactions.
Redaction markers
Each match is replaced with a [REDACTED_<TYPE>] marker. The built-in PII types and their markers:
| PII type | Marker |
|---|---|
email | [REDACTED_EMAIL] |
phone | [REDACTED_PHONE] |
credit_card | [REDACTED_CREDIT_CARD] |
ssn | [REDACTED_SSN] |
ip_address | [REDACTED_IP] |
api_key | [REDACTED_API_KEY] |
Inspect redactions
Each entry in result.redactions is a Redaction with .pii_type, .start_position, .end_position, and .original_length (positions index into the original text).
from briefcase.sanitize import Sanitizer
sanitizer = Sanitizer()result = sanitizer.sanitize("Call 555-123-4567 or email jane.doe@example.com")
for redaction in result.redactions: print(redaction.pii_type, redaction.start_position, redaction.end_position)# phone 5 21# email 27 43Sanitize JSON
sanitize_json() walks a dict and redacts string values, returning a SanitizationJsonResult with .sanitized and .redaction_count. Useful for sanitizing a structured ticket payload before you record it.
from briefcase.sanitize import Sanitizer
sanitizer = Sanitizer()record = { "ticket_id": "TKT-4821", "contact_email": "jane.doe@example.com", "priority": 2,}
result = sanitizer.sanitize_json(record)print(result.sanitized)# {'contact_email': '[REDACTED_EMAIL]', 'priority': 2, 'ticket_id': 'TKT-4821'}print(result.redaction_count) # 1Reject sensitive data in a guardrail
Sometimes you don’t want to redact and continue — you want to stop. Use
contains_pii (a fast boolean) or analyze_pii (a summary that doesn’t modify
the text) to refuse a payload before it’s ever recorded.
from briefcase.sanitize import Sanitizer
sanitizer = Sanitizer()
def guard(text: str) -> None: if sanitizer.contains_pii(text): report = sanitizer.analyze_pii(text) # summary for logging the reason raise ValueError(f"refusing to store record: PII detected ({report})")
guard("Email jane.doe@example.com") # raises before classify_ticket is recordedreport = sanitizer.analyze_pii("Email jane.doe@example.com and call 555-123-4567")print(report)# {'has_pii': True, 'total_matches': 2, 'unique_types': 2,# 'detected_types': ['phone', 'email']}| Method | Returns | Use it to… |
|---|---|---|
sanitize(text) | SanitizationResult | Strip PII and keep going |
sanitize_json(data) | SanitizationJsonResult | Strip PII from a structured payload |
contains_pii(text) | bool | Cheaply gate a guardrail — proceed or reject |
analyze_pii(text) | summary dict | Get the details (types, counts) for logging or decisions |
This pairs naturally with Guardrails, where you can run
this check inside an evaluate() and return DENY when PII is still present.
Custom patterns
Register your own patterns for identifiers specific to your domain — a ticket
number scheme, an internal account ID format — with add_pattern(name, regex).
The marker uppercases the name, so ticket_id redacts to [REDACTED_TICKET_ID].
Registered patterns are picked up by sanitize, contains_pii, and
analyze_pii.
from briefcase.sanitize import Sanitizer
sanitizer = Sanitizer()sanitizer.add_pattern("ticket_id", r"\bTKT-\d{4}\b")
result = sanitizer.sanitize("Ticket TKT-4821 was escalated")print(result.sanitized) # Ticket [REDACTED_TICKET_ID] was escalated| Argument | Type | Description |
|---|---|---|
name | str | A label for the pattern; uppercased into the [REDACTED_<NAME>] marker and reported by analyze_pii |
pattern | str | The regex to match and redact |
remove_pattern(pattern_name) removes a registered pattern again.
Key classes
Sanitizer— detects and redacts PII;sanitize,sanitize_json,add_pattern,remove_pattern,contains_pii,analyze_pii.SanitizationResult—.sanitized,.redactions,.redaction_count,.has_redactions.Redaction—.pii_type,.start_position,.end_position,.original_length.SanitizationJsonResult—.sanitized,.redaction_count.