June 18, 2026
Redacting PII Before It Ever Reaches an LLM
The problem with pasting logs into a chat window
Incident logs are full of things you don't want leaving your network: internal IP ranges, customer emails, API keys, session tokens, hostnames that map straight to your topology. The fastest way to triage an incident is often to paste the relevant log lines into an AI assistant — and that's exactly the moment most teams accidentally leak something they shouldn't.
TRCAA's triage flow refuses to send raw log content to any AI provider, cloud or local, without running it through a redaction pass first.
How detection works
PiiDetector::detect(&str) runs a set of pattern matchers over the uploaded log file — IPv4/IPv6 addresses, email addresses, common credential and token shapes, and a handful of other span types — and returns a list of non-overlapping matches. When two patterns match overlapping text, the longest match wins, so a token embedded inside a longer credential string doesn't get partially redacted in a way that leaves a fragment behind.
Each match carries a byte-offset span and a replacement token ([IPv4], [EMAIL], and so on). The redactor applies these in reverse order, from the end of the file backward, so replacing one span never shifts the offsets of the ones still waiting to be applied.
Review before it's sent, not after
Redaction isn't silent. Before any AI call goes out, the triage UI shows a before/after diff of exactly what's being redacted, so you can confirm nothing important got swept up (or nothing sensitive got missed) before it leaves your machine.
The audit trail
Every redaction event is logged: apply_redactions runs, and a SHA-256 hash of the resulting sanitized text is recorded via write_audit_event before the request goes to any provider — local Ollama or cloud. If you ever need to answer "what exactly did we send to a third-party AI service during this incident," the hash trail is there, without needing to store the sensitive original text anywhere near the audit log itself.
This is the same reason the database is encrypted at rest in production builds (SQLCipher, AES-256) and why credentials in settings are stored via AES-256-GCM rather than plaintext — the assumption throughout is that incident data is sensitive by default, not sensitive by exception.