Skip to main content
When you need to mask sensitive data an llm prompt carries — emails, card numbers, national IDs, secrets — the gateway rewrites each match in place before the model sees it. A masked value becomes a typed tag (jane@acme.com[EMAIL]), so the model still reads a coherent prompt while the raw value never leaves your workspace. This page is the focused take on what masking renders, how to change the tag, and how to mask some entities while blocking others on a single rule. For the full engine — every rule type, stage, and route — see the Guardrails reference, and for masking on the request specifically, Input-stage rules.

1. Mask sensitive data llm prompts carry, with typed tags

A pii rule with the mask action detects an entity and replaces each match with a typed redaction tag — an uppercased label in brackets that names what was removed without revealing the value:
EntityRendered tag
email[EMAIL]
credit_card[CREDIT_CARD]
ssn[SSN]
The full built-in detector set — email, phone, credit_card, ssn, ip, iban, mac_address, jwt, aws_access_key, api_key_openai, bitcoin_address, plus regional jp_mynumber, kr_rrn, and cn_resident_id — each renders its own bracketed tag ([PHONE], [IBAN], [JP_MYNUMBER], and so on). The tag is deterministic: the same entity always renders the same label, so downstream prompts stay stable and your logs read cleanly.
Typed tags beat a blanket [REDACTED] for model quality. The model still knows it’s looking at an email vs. an account number vs. a phone number, so it can keep reasoning about the shape of the data — “reply to [EMAIL]” stays an actionable instruction — without ever holding the real value.
Input masking is fully live — the gateway rewrites the prompt before it reaches the model, streaming or not. Output masking is live on non-streaming responses too: a mask rule on the output stage rewrites the completion before it returns. Only streaming output masking is on the roadmap; on a streamed reply, prefer block at the output stage. See Streaming coverage for the exact stage/stream matrix.

2. One concrete example

Author the rule in the console under your own session — guardrail config requires Developer+, not a relay key. Add a single pii rule to a guardrail named pii-shield:
{
  "type": "pii",
  "stage": "input",
  "action": "mask",
  "entities": ["email", "phone", "ssn"]
}
Attach it to a key (set guardrail_id, or mark it the workspace default — see Attach to a key), then call the gateway with that sk-orca-... relay key:
curl https://api.orcarouter.ai/v1/chat/completions \
  -H "Authorization: Bearer sk-orca-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-4o-mini",
    "messages": [
      {"role": "user", "content": "Reply to jane@acme.com about her SSN 123-45-6789"}
    ]
  }'
The gateway rewrites the prompt to “Reply to [EMAIL] about her SSN [SSN] before forwarding. The upstream model never sees the address or the number. Prove the exact rendering in the editor’s Test tab first (no upstream call, no quota) — see Testing & eval.

3. Override the tag with mask_with

Built-in entities render a fixed tag. Custom entities — your own regex detectors layered on top of the built-in set — let you set the replacement text yourself with mask_with:
{
  "type": "pii",
  "stage": "input",
  "action": "mask",
  "custom_entities": [
    {
      "name": "employee_id",
      "pattern": "EMP-[0-9]{6}",
      "mask_with": "[STAFF_ID]"
    }
  ]
}
mask_with is the verbatim replacement string for that entity’s matches. EMP-004217 becomes [STAFF_ID]. Leave it empty and the match renders the default tag [<UPPERCASE_NAME>] — here, [EMPLOYEE_ID] — so a custom detector always produces a readable, typed redaction even with no override.
name (lowercase ASCII / digits / underscore, must start with a letter), pattern (a Go RE2 regex — linear-time, no backreferences), optional checksum (luhn validates card-shaped numbers), and optional mask_with. Up to 25 custom entities per rule — each is a scan over the full text, so the cap keeps the hot path linear. See Custom PII entities.
A name flows into audit logs and the Matches feed unquoted, so keep it to lowercase ASCII letters, digits, and underscores starting with a letter (e.g. employee_id, internal_ticket). The validator rejects anything else.

4. Mask some entities, block others — entity_actions

A single pii rule can apply different actions to different entities via entity_actions, instead of stacking three overlapping rules. The classic shape: mask low-sensitivity contact data, but block the high-sensitivity fields outright.
{
  "type": "pii",
  "stage": "input",
  "action": "mask",
  "entities": ["email", "phone", "ip", "credit_card", "ssn"],
  "entity_actions": {
    "credit_card": "block",
    "ssn": "block"
  }
}
Here email, phone, and ip follow the rule’s top-level mask and render [EMAIL] / [PHONE] / [IP]; a credit_card or ssn match instead blocks the whole request with HTTP 400 guardrail_blocked.
FieldRule
KeysMust be an entity declared on the rule (built-in or custom).
Valuesblock, mask, flag, or annotate.
A blocked request costs no quota — an input-stage block fires before metering. A masked request goes through with the sanitized text. So one rule can quietly redact the routine fields and hard-stop the regulated ones, with a single attachment and no application change.

5. Mask vs. block vs. flag

Masking is one of the actions a rule (or per-entity override) can take. Pick by how much you want to disturb the traffic:

mask

Redact the match to a typed tag and let the request through with the sanitized text. The model never sees the raw value.

block

Reject the whole request with HTTP 400 guardrail_blocked. Nothing reaches the model. Use it for data that must never transit.

flag

Change nothing about the traffic — only record a match. Measure how often a rule would fire before you enforce it.
A good rollout is flag → mask → block: flag to size the impact, mask once you trust the detector, and reserve block for the fields you can’t let through at all. See Actions and Tune false positives.

6. Verify what got masked

Every rule that fires records a match in the workspace Matches feed — rule type, action, stage, and a detail string. The matched substring itself (the raw email, the actual card number) is recorded only when Log raw content is on, which is off by default — the privacy-conservative posture, since the whole point is to keep raw values out of your logs.
Turn Log raw content on only when you genuinely need the substring for triage, and only per guardrail. With it off, the feed proves a [CREDIT_CARD] was masked without ever storing the number. The toggle is non-retroactive. See Logging & privacy.

7. Where to go next

  • PII Shield preset — the one-rule, mask-everything starting point you can apply in a click.
  • Custom PII entities — author your own regex detectors with mask_with and optional luhn.
  • Input-stage rules — where masking runs live today, before the model and before metering.
  • Block secrets — for credentials, blocking (not masking) is the right call.
  • Streaming coverage — which stage/stream combinations mask vs. block today.
Read the Guardrails reference for the complete engine, or PII exposure and secret leakage for the threats masking is built to contain.