# PII protection

> How Prompt Guard detects personal and sensitive data with pattern matching and model-backed AI detection, and how NER IDs pseudonymize values without breaking the model's ability to reason over them.

Blanking every sensitive value to the same placeholder protects the data, but it destroys the relationships a model needs to give a useful answer. NER IDs resolve that tension: a value is replaced with a stable pseudonym instead of a generic token, so the model still reasons over faithful structure while the real value never reaches the provider. [Pseudonymize PII with NER IDs →](/products/affinidi-trust-fabric/agent-stream/how-to-guides/guardrails/pseudonymize-pii-with-ner-ids.md)

## Two ways Prompt Guard finds PII

Prompt Guard, introduced in [Guardrails →](/products/affinidi-trust-fabric/agent-stream/concepts/guardrails.md), combines two complementary detectors:

- Pattern matching. Deterministic detection of well-shaped values, such as emails, social security numbers, credit card numbers, phone numbers, and IP addresses, plus any custom pattern you define. Fast, free, and self-contained.

- AI matching. A model-backed detector for free-form PII that patterns cannot express, such as people’s names, street addresses, organisations, and locations by default, extendable to other entity types you configure, such as dates of birth or passport numbers. It is language-agnostic and needs no word lists.

A surface can carry several AI detectors on one entry. They run concurrently, so added latency is bounded by the slowest detector rather than the sum of all of them. Their results also share one NER ID scheme, so a value two detectors both catch still gets a single pseudonym.

Request and response are not symmetric:

  Request sideBoth pattern matching and AI matching run, since this is where PII enters the system.
  Response sideOnly pattern matching runs. AI matching is a request-side-only detector.

## Three actions when PII is found

For each detector, you choose what happens when it finds a match:

| Action | What happens |
| Reject | Block the call and return a response you control. The provider is never called. |
| Redact | Replace every match with a static placeholder, such as <EMAIL>. Simple, but lossy: two different values become indistinguishable. |
| NER ID | Replace each distinct value with a stable pseudonym, such as [EMAIL_NER_001], reused for that exact value everywhere it appears in the request. |

## NER ID

A NER ID is the stable pseudonym Prompt Guard substitutes for a detected value when the action is set to pseudonymize rather than redact. Redaction and pseudonymization solve the same problem differently, and the difference shows up most clearly when a request mentions more than one person.

Take a prompt that mentions two different people, each with their own address and email: “Sarah Chen lives at 12 Elm Street and her email is [sarah.chen@example.com](mailto:sarah.chen@example.com). James Cole lives at 88 Oak Avenue and his email is [james.cole@example.com](mailto:james.cole@example.com). Draft a personalised welcome email to each person.”

  Static redaction<PERSON> lives at <ADDRESS> and their email is <EMAIL>. <PERSON> lives at <ADDRESS> and their email is <EMAIL>. Draft a personalised welcome email to each person.

Both people collapse into one indistinguishable shape. The model can no longer tell which address or email belongs to which person, so it cannot draft two distinct, correctly addressed emails.
  NER IDPERSON_NER_001 lives at ADDRESS_NER_001 and their email is EMAIL_NER_001. PERSON_NER_002 lives at ADDRESS_NER_002 and their email is EMAIL_NER_002. Draft a personalised welcome email to each person.

The model can still tell that PERSON_NER_001's address and email belong together, and are distinct from PERSON_NER_002's, without ever seeing either person's real name, address, or email.

The provider only ever sees the masked version. It drafts its reply using the same pseudonyms, for example replying to “Hi PERSON_NER_001” with the welcome kit sent to “ADDRESS_NER_001”.

Nothing between masking and restoration ever sees a real value: not the provider, not the Decider, not the Judge, not the Jury. Only the final restoration step swaps the pseudonyms back, and only for the caller.

## Restoring NER IDs in the response

When restore-in-response is enabled, the real values are swapped back into the model’s answer before it reaches the caller. This restoration runs last, after every model-facing stage: the provider call, the Decider, the Judge, the Jury, and response expert witnesses. None of those stages ever see anything but pseudonyms.

Detection, masking, and restoration all cover more than plain message text: they also apply to assistant tool_calls[].function.arguments, the JSON string a tool call carries, so a value the model echoes back inside a tool call’s arguments is masked and restored the same as one in message content.

Restoration also works on a streamed response, with a few differences from the buffered path:

- Chunk boundaries are handled. A NER ID token can arrive split across more than one Server-Sent-Events chunk, so the streaming path buffers a partial token at a chunk boundary rather than restoring prematurely and leaking half a token to the caller.

- Only delta.content is covered. A NER ID inside a streamed tool-call argument fragment is not restored, since tool-call arguments are only fully known once the stream completes.

- The buffered path has no such gap. It restores NER IDs in the model’s own tool_calls arguments as well as in message content.

## How pseudonyms stay linked across a conversation

Three mechanisms make pseudonymized text read naturally across a longer conversation: one always on, and two you opt into.

- Name-variant linking is always on, deterministic, and needs no configuration. Whenever the AI detector reports a PERSON value whose name tokens are a subset or superset of a person already seen in the request, it reuses that person’s NER ID instead of minting a new one, so “John Smith,” “John,” and “Dr. Smith” all collapse to the same PERSON id. Comparison ignores case, punctuation, and honorifics. An ambiguous bare surname that could match more than one known person, such as “Smith” after both “John Smith” and “Jane Smith”, is left unlinked rather than guessed.

- Deterministic pronoun linking is a regex-based feature, unrelated to the AI detector, that links a singular gendered pronoun, such as “he” or “she”, to the one PERSON NER ID seen so far in the text. It is opt-in, free, and has no effect on caching.

- AI coreference linking asks the model-backed detector to recognise that different mentions, such as “Bob” and “Robert Smith”, refer to the same real-world entity, and collapses them to one shared NER ID. It is opt-in and only affects the AI detector; it has no effect on pattern matching or on the other two mechanisms.

Coreference linking has a real performance cost, because of how it interacts with detection caching:

  Coreference off (default)Cached at message granularity. In a multi-turn conversation the client resends prior history verbatim, so every earlier message is a cache hit and only the newest turn is sent to the detector.
  Coreference onCached at whole-prompt granularity. The detector must see every mention together to link them, so each turn re-scans the entire, ever-growing conversation.

This is not a caching limitation to be fixed. Recognising that an earlier and a later mention are the same entity fundamentally requires the model to see both mentions in the same call.

Leave coreference off for the lowest cost and latency. Turn it on only when the value of linking aliases and repeated mentions to one shared identifier outweighs the added token cost of re-scanning the growing conversation on every turn.

## How the AI detector is hardened against misuse

Because the AI detector is a model that the request text is sent to, it carries its own protections, independent of the rest of the pipeline:

- Detection stays in your control. Point the detector at a model you trust, ideally self-hosted or otherwise local, since the text to inspect is sent to it.

- The endpoint is SSRF-checked, using the same cloud-metadata and unsafe-target validation applied to every other operator-supplied endpoint, described in [Security and access control →](/products/affinidi-trust-fabric/agent-stream/concepts/security-and-access-control.md).

- Input is bounded, so a very large prompt cannot run up unbounded detector cost or latency.

- The inspected text is injection-resistant. It is wrapped in a per-call random delimiter with an enforced instruction that the model must treat it strictly as data, so a caller cannot embed an instruction telling the detector to ignore their own PII.

- No raw values are persisted. The pseudonym-to-value map exists only for the life of the request, and the detection cache holds values in memory only, never on disk.

## How PII detection shows up in governance records

When the AI detector runs on a surface with [governance recording](/products/affinidi-trust-fabric/agent-stream/concepts/governance-records.md) enabled, it adds its own stage to the record. That stage shows either that a number of PII values were masked, or that the detector was unavailable and the request continued on regex masking alone.

The stage proves the control ran without exposing the value map itself. Governance records store the original request and the restored completion, but never the pseudonym-to-value mapping.

## Why this matters

Static redaction and sending raw prompts to a provider sit at opposite extremes. One protects the data and breaks the answer; the other protects the answer and loses control of the data. NER IDs let a model reason over realistic, well-formed text without ever seeing the real values, which is what makes Prompt Guard usable on genuinely sensitive, free-form conversations, such as customer support and case-handling, rather than only on structured fields a regex can already catch.

For a regulated organisation, this is the difference between disabling an AI feature over data-handling risk and shipping it with a defensible, auditable control in place.

## Related

- [Guardrails](/products/affinidi-trust-fabric/agent-stream/concepts/guardrails.md): Where Prompt Guard sits alongside Expert Witnesses, Judge, and Jury.

- [Pipeline and stages](/products/affinidi-trust-fabric/agent-stream/concepts/pipeline-and-stages.md): Where request-side masking and response-side restoration sit relative to the provider call.

- [Governance records](/products/affinidi-trust-fabric/agent-stream/concepts/governance-records.md): How a PII detection stage is captured without exposing the values it protected.

- [Security and access control](/products/affinidi-trust-fabric/agent-stream/concepts/security-and-access-control.md): The SSRF protection the detector endpoint shares with every other operator-supplied endpoint.

- [Pseudonymize PII with NER IDs](/products/affinidi-trust-fabric/agent-stream/how-to-guides/guardrails/pseudonymize-pii-with-ner-ids.md): Step-by-step guide to configuring NER ID pseudonymization on a surface.
