Skip to main content

One Detector, Two Exits

Updated 4 min readMarkdown

Most teams meet PII detection at one door: the guardrail. A user pastes something personal into a prompt, the detector spots it, and the value is stripped or blocked before the request reaches the model provider. That door matters. It is also only half the building.

The same request has a second exit. Seconds after the provider answers, the request is written to your own log store — and in most systems it is written as it arrived, personal data included. A team can run a careful guardrail on the way out to the provider and a verbatim firehose into its own storage, and feel covered by the first while the second quietly accumulates the exact dataset the guardrail existed to keep out of third-party hands. The leak was not closed. It was relocated to a store the team owns, retains longer, backs up more faithfully, and reviews less often.

The same eyes, pointed at both doors

The practical resolution is that these are not two systems. Detection is one capability with two places it has to run: before the prompt leaves for the provider, and before the record lands in the log store. Same entity types, same policy, two exits from the request path. Configuring them separately is deliberate — a team may want the provider to receive a value the log must never keep, or the reverse — but running only one is not a partial implementation. It is a decision about which copy you are protecting, made usually without noticing you made it.

What the log exit does differently

Redaction at the log exit is not deletion of the message. The detected span is replaced in place with a typed placeholder, so a stored request reads as a support question with an [EMAIL] and a [PHONE] in the second message, not as a blank. Everything an incident review runs on — ordering, roles, token counts, the model, the error — survives untouched.

Three details separate a real implementation from a gesture:

Metadata goes through the same pass. The requester IP sitting in the metadata field is personal data in its own right. So are identifying headers and the free-text tags that collect addresses because they make dashboards readable. Body-only redaction leaves the same class of data one field over.

The event never quotes the match. When the detector fires, the audit record carries the detector, the type, the scope and the request id. A record that quotes what it caught re-stores the value in a second system, frequently a less guarded one.

Uncertainty resolves toward redaction. A string that might be a national ID and might be an order number gets replaced. A false positive costs a vaguer log line. A false negative costs a stored identifier that then propagates to every backup and export. The two errors are not priced the same, so the tie-break should not treat them as if they were.

The store that results

What accumulates under this design is a log a team can be relaxed about in the specific ways that matter. Exports carry no prompt text to leak. A deletion request does not have to hunt values that were never written. A privacy review reads a system whose default state is clean rather than a system whose cleanliness depends on every future reader behaving.

The honest boundaries still apply. Detection is statistical, and unusual formats pass. A redacted record combined with timestamps and key identity can still single out a session, which makes the log pseudonymised rather than anonymous, with the access controls and retention limits that status requires. And the guardrail question — what the provider itself receives — remains its own decision, upstream of everything here. The complete treatment, from the typed placeholders to the headers that carry the operational facts without carrying content, is in the PII redaction in logs deep dive on nRouter's engineering blog.

About the author

  • nRouter.ai - Every model. One API key. Total control. Guardrails, budget enforcement, and smart routing included on every plan.

No comments yet. Be the first to comment.