promptdojo_

The PII proxy — mask before the model, unmask for the named human — step 1 of 8

The ticket that left the building

Vera's exceptions desk drafts replies to members whose orders failed. Tonight's ticket: member MBR-104221, clinic email, a 555 callback number, a one-line note that the refill is late. Someone pastes the whole thing into the vendor model because the model is genuinely good at the draft — warm, specific, done in ten seconds.

The draft is usable. The leak is not a vibe. The raw member ID, email, and phone are now in a vendor log. The model did exactly what it is for. It has no duty to refuse identifiers. Nothing in the send path asked whether those values were allowed to leave.

Why this exists (and what this lesson is not)

HIPAA and SOC 2 are why the vendor review keeps asking what customer data a model sees. A vendor model is outside the building. Raw member identifiers don't go with it. That is the reason. This is not a compliance class: no BAA walkthrough, no Trust Services Criteria, no advice about what your lawyer would file. The control you can actually write is a proxy.

The three rules of the proxy

  1. Mask before the model. Every known identifier in the ticket becomes a token — [MEMBER_1], [EMAIL_2], [PHONE_3]. The outbound payload is the ticket with those values gone. If a known value is still in the outbound text, the send is refused. The model drafts against tokens.
  2. Unmask after, for a named human. The draft comes back with tokens in it. A token map restores the real values. Restoration is not "the system." It is Vera, or Miguel — a person who will send the reply and can be asked about it later.
  3. auto does not get the real values. The same line you already drew for checklists: the machine may compute and draft; it may not hold the identifiers. A proxy that unmasks into a log, a vendor payload, or an approval: auto path is the paste bug with extra steps.

A proxy that satisfies all three has the property this lesson is built on: the model can draft the exception reply without ever seeing the member, and the named human can send it without ever typing the identifiers back in by hand.

The next step turns these rules into a data structure — because a rule you can't lint is a rule that erodes.