Unit 12.01: Redaction on the way in
Redact on the way in. A log that captures raw content and promises to clean it later is personal data with a plan attached.
Structured identifiers, caught by pattern
Account numbers, emails and card numbers replaced before writing.
The code redacts a realistic string.
import re
PATTERNS = [
(re.compile(r"\bACC-\d+\b"), "[ACCOUNT]"),
(re.compile(r"[\w.+-]+@[\w-]+\.[\w.]+"), "[EMAIL]"),
(re.compile(r"\b\d{4}[ -]?\d{4}[ -]?\d{4}[ -]?\d{4}\b"), "[CARD]"),
]
def redact(text):
for pattern, replacement in PATTERNS:
text = pattern.sub(replacement, text)
return text
RAW = "[email protected] on ACC-1187, card 4111 1111 1111 1111"
print("raw :", RAW)
print("redacted:", redact(RAW))
print("""
Redact on the way in, not on the way out. A log that captures raw content and
promises to clean it later is personal data with a plan attached.
What this catches is structured identifiers. A customer writing their own name
and address in free text matches no pattern, which is why retention and access
control do the rest.
""")
All three structured identifiers are caught. What is not caught is a customer writing their own name and address in free text, which matches no pattern and is just as much personal data.
So redaction reduces exposure and does not remove it - which is why the next unit's retention limits are not optional.
The mistake this prevents
The mistake is treating redaction as sufficient and skipping retention. A log store with good redaction and no limit accumulates years of partially-redacted personal data in a system reviewed less carefully than the primary one.
Takeaway
Redact structured identifiers before writing, and treat it as reduction rather than removal. Free-text personal data matches no pattern.
