The gateway scans every inference request for personally identifiable information (PII) and replaces what it finds before the request leaves your network. Use it when prompts may carry customer emails, card numbers or national IDs that must never reach a model provider or sit in your logs in plaintext.

How it works

  1. After policy checks and the prompt injection firewall, the gateway runs the configured detector over every message’s text content, prompt and input.
  2. Each finding is replaced in place. Without a vault key the replacement is [REDACTED:<TYPE>]. With a vault key it is a numbered token such as [PII_1], and the original value is stored encrypted beside the request trace.
  3. Everything downstream sees only the redacted text: input guardrails, the cache key, the provider, the audit log and exported trace spans.
  4. When the model answers, the completion is scanned too. What reaches your client depends on the model’s pii_output_mode.
sent by the caller   My Aadhaar is 2345 6789 0123 and my email is arun@example.com.
sent to the model    My Aadhaar is [PII_1] and my email is [PII_2].            (vault key set)
                     My Aadhaar is [REDACTED:AADHAAR] and my email is [REDACTED:EMAIL].  (no key)

Configuration

pii:
  detector: builtin          # builtin (default) | http | off
  http_url: ""               # required when detector: http
  vault:                     # optional: makes request redaction reversible
    keys:
      v1: ${PII_KEY_V1}      # base64 of exactly 32 bytes
    current_key: v1          # may be omitted when only one key is set

models:
  - logical_name: gpt-4o
    pii_output_mode: passthrough   # passthrough (default) | buffer

Key fields

pii.detector
string
default:"builtin"
builtin runs the in-process regex detector. http calls your detection sidecar at pii.http_url. off disables detection entirely. Any other value stops startup.
pii.http_url
string
The full URL the gateway POSTs to, path included. Required when detector is http.
pii.vault.keys
map
Version name to base64-encoded 32-byte AES-256 key. Standard or URL-safe base64, with or without padding. A key that is not exactly 32 bytes stops startup rather than silently falling back to one-way redaction. Version names are 1–32 letters, digits, - or _.
pii.vault.current_key
string
The version new values are sealed with. Required when more than one key is configured.
models[].pii_output_mode
string
default:"passthrough"
How the completion is handled. See Outbound PII.
The detector and vault are built once when the gateway process starts, from gateway.yaml and the environment, so a change needs a restart.

Detectors

Built-in entities

EntityMatches
EMAILEmail addresses
EMIRATES_IDUAE Emirates ID (784-YYYY-NNNNNNN-C, dashes optional)
IBANIBANs, mod-97 checked
CREDIT_CARD13–19 digit card numbers, Luhn checked
AADHAARIndia Aadhaar: 12 digits in groups of four
PANIndia PAN: five letters, four digits, one letter
SAUDI_IDSaudi national ID / iqama: 10 digits starting with 1 or 2
PHONEInternational numbers starting + or 00
IP_ADDRESSIPv4 addresses
When two matches overlap, the entity higher in this table wins, so an IBAN’s digits are not also reported as a phone number.

HTTP sidecar

With detector: http the gateway sends each text to your service and redacts the spans it returns. Use this for NER-grade detection (names, addresses, other languages).
POST {pii.http_url}
Content-Type: application/json

{"text": "Call Priya at +971 50 123 4567"}
start and end are byte offsets into text; spans outside the text are ignored. entity_type becomes the <TYPE> in the placeholder. The call times out after 10 seconds, and any non-200 status is treated as a detection failure.
Detection fails open. If the detector errors (sidecar down, timeout, bad JSON), the gateway logs a warning and the request continues unredacted. Monitor your sidecar’s availability if redaction is a compliance requirement.

Outbound PII

The completion text is always scanned and the redacted copy is what the audit log and the cache store. pii_output_mode decides what the client receives:
ModeClient receivesLatency
passthroughThe provider’s response as it streams, unredacted.No added latency.
bufferThe full response, buffered, with PII replaced by [REDACTED:<TYPE>]. Streamed requests are replayed as a stream after the scan.Time to first token becomes time to last token.
Output redaction is always one-way; the vault applies only to the request.

Reversible redaction

With a vault key configured, each redacted value is encrypted with AES-256-GCM and stored alongside the trace, bound to its organization, trace, token and position. Values are stored only when the request body itself is recorded (see Request Logging); a request sent with X-ManyLayers-Store-Logs: false keeps no values.
1

Generate a key

MANYLAYERS_PII_VAULT_KEYS="v1:$(openssl rand -base64 32)"
MANYLAYERS_PII_VAULT_KEY_VERSION=v1
Set the same values on every gateway and workspace instance, because the gateway seals values and the console reveals them. These variables override pii.vault in the YAML.
2

Reveal an original

A caller holding gateway.traces.sensitive.read (Gateway admins by default) opens a trace in Request Traces and selects Show Original, or calls the API:
curl -X POST "https://app.manylayers.io/admin/audit/$TRACE_ID/original?workspace_id=$WS" \
  -H "Authorization: Bearer ml_pat_..."
$TRACE_ID is the X-ManyLayers-Trace-Id response header of the original request. The response holds id, request_body (tokens replaced by their values) and restored (how many changes were undone), and is sent with Cache-Control: no-store. Every attempt, allowed or denied, is written to the organization’s access log.
Add a new version and make it current: MANYLAYERS_PII_VAULT_KEYS="v1:<old>,v2:<new>" and MANYLAYERS_PII_VAULT_KEY_VERSION=v2, then restart. New values are sealed with v2; existing values keep decrypting with v1. Remove v1 only after every trace it sealed has aged out of audit retention — a removed version makes its values unreadable.
The endpoint returns 409 not_reconstructable rather than a possibly wrong original when the caller’s own text already contained a [PII_n]-shaped string, when two rewrites left identical text from different originals, or when the stored body no longer matches its recorded changes. It returns 404 when the body was not recorded or nothing was redacted reversibly, and 503 pii_vault_not_configured when the service has no key.
To keep prompts intact for the model but scrub the stored copy, set pii.detector: off and add a logging config with redaction.pii: true. See Request Logging.
Gateway redaction runs before every guardrail. A pii guardrail adds category-level control per workspace and rule; both can run together, and the guardrail sees the already-redacted text.

Next steps

Guardrails

Add per-workspace PII, secrets and regex checks on input and output.

Request Logging & Audit

Control which bodies are stored and how they are redacted.

Caching

How redacted requests form cache keys.

Prompt Injection Firewall

The check that runs just before redaction.