PII Redaction Configuration

View as Markdown

Use this page when you want to configure the built-in PII redaction plugin component. The component kind is pii_redaction.

The CLI and primary language bindings register this component. Direct Rust applications must call nemo_relay_pii_redaction::component::register_pii_redaction_component() before they validate or initialize a pii_redaction component.

For plugin file discovery, precedence, merge behavior, editor controls, and gateway conflict rules, refer to Plugin Configuration Files.

NeMo Relay plugin configuration uses the generic plugin document shape, so field names stay snake_case in every binding and in plugins.toml.

Relation to Raw Middleware

This plugin uses the same sanitize-guardrail middleware family documented in Middleware.

The difference between raw middleware and pii_redaction is the layer of abstraction:

  • Raw middleware asks you to register sanitize callbacks directly in code.
  • pii_redaction gives you a first-party, config-driven privacy contract on top of those same runtime hooks.

Choose pii_redaction when you want a reusable built-in policy surface. Choose raw middleware when you need bespoke callback logic that does not fit the plugin contract.

Plugin Versus Middleware

Use this matrix when deciding whether to use the built-in pii_redaction plugin or raw sanitize-guardrail middleware directly.

Areapii_redaction PluginRaw Middleware
Primary UXDeclarative config through plugins.toml, bindings helpers, and the CLI editorCallback registration in application code
Best fitReusable privacy policy shared across apps or teamsApp-specific logic tied to runtime state or custom heuristics
Built-in actionsremove, redact, regex_replace, hash, maskYou implement the behavior yourself
Built-in detectorsSupportedYou implement the matcher yourself
Codec-aware LLM handlingSupported for the documented codecsYou handle normalization and provider shapes yourself
Validation and editor supportSupportedNot provided
Cross-runtime consistencyFirst-party contract across Relay surfacesDepends on each app’s callback code
FlexibilityLimited to the plugin contractFull control over sanitize behavior
When to choose itYou want the fastest path to a supported privacy surfaceYou need behavior the plugin contract does not express

Component Shape

The top-level PII redaction object contains:

FieldPurpose
versionPII redaction config schema version. Defaults to 1.
modeBackend mode. Current values are builtin and local_model. Defaults to builtin.
inputEnables managed LLM request sanitization and non-tool, non-LLM scope-start field sanitization. Defaults to true.
outputEnables managed LLM response sanitization and non-tool, non-LLM scope-end field sanitization. Defaults to true.
markEnables mark data, category_profile, and metadata sanitization. Defaults to true.
tool_inputEnables sanitization of emitted tool-request observability payloads. Defaults to true.
tool_outputEnables sanitization of emitted tool-response observability payloads. Defaults to true.
priorityGuardrail priority. Lower values run earlier. Defaults to 100.
codecManaged LLM provider codec. Required when input or output is enabled.
profilesOrdered redaction profiles. Each profile selects builtin or local_model; enabled profiles cover every supported sanitization surface.
builtinBuilt-in backend settings used when mode = "builtin".
localLocal-backend settings used when mode = "local_model".
policyComponent-local handling for unknown fields and unsupported values.

At least one managed redaction surface must be enabled.

Use either the legacy single-policy fields (mode, surface flags, priority, builtin, and local) or profiles, but not both. The component-wide codec, version, and policy fields remain valid with profiles.

In profile-array mode, profiles execute by ascending priority and use array order to break ties. Relay assigns internal names such as profile_0, so profiles do not require IDs. Disabled profiles are validated but do not register callbacks. The complete array is replaced as one value during config layering.

Backend Support

The following table compares the available PII redaction backends:

Areabuiltinlocal_model
Built-in component kind and config validationSupportedSupported
Managed LLM inputSupportedNot implemented
Managed LLM outputSupportedNot implemented
Mark and generic scope event fieldsSupportedNot implemented
Managed tool_inputSupportedNot implemented
Managed tool_outputSupportedNot implemented
Built-in actionsremove, redact, regex_replace, hash, maskN/A
Codec supportopenai_chat, openai_responses, anthropic_messagesRuntime-specific future implementation
Runtime availabilityAny runtime that includes the nemo-relay-pii-redaction plugin crateRuntimes that install a local backend provider

Built-in Mode

Use builtin mode when NeMo Relay should sanitize emitted observability payloads with a deterministic first-party backend.

This is the recommended mode when the privacy behavior is common enough to be described declaratively with built-in actions, detector presets, exact target paths, and supported codecs.

Requirements

To use mode = "builtin":

  • builtin settings are required.
  • codec is required when input or output is enabled.
  • builtin.action must be remove, redact, regex_replace, hash, or mask.
  • builtin.pattern or builtin.detector is required when builtin.action = "regex_replace" or builtin.action = "redact".

Composed plugins.toml Example

You can write this config directly in plugins.toml, or create and edit it through the CLI with nemo-relay plugins edit. For plugin file discovery, precedence, merge behavior, and editor controls, refer to Plugin Configuration Files.

1version = 1
2
3[[components]]
4kind = "pii_redaction"
5enabled = true
6
7[components.config]
8version = 1
9codec = "openai_chat"
10
11[[components.config.profiles]]
12mode = "builtin"
13priority = 80
14
15[components.config.profiles.builtin]
16action = "redact"
17detector = "email"
18
19[[components.config.profiles]]
20mode = "builtin"
21priority = 90
22
23[components.config.profiles.builtin]
24action = "redact"
25detector = "api_key"
26
27[components.config.policy]
28unknown_component = "warn"
29unknown_field = "warn"
30unsupported_value = "error"

This example applies email redaction before API-key redaction to marks, LLM and tool observability payloads, and scope metadata. [REDACTED] is already the default replacement for redact, so no replacement field is needed.

Legacy single-policy configurations may still use mark and the other surface flags. Profile-array configurations intentionally do not expose those flags: every enabled profile owns the complete pre-subscriber sanitization boundary.

CLI Editor Support

The NeMo Relay CLI plugin editor now exposes pii_redaction directly through nemo-relay plugins edit.

Use the editor when you want to:

  • Toggle the component on or off
  • Choose builtin or local_model
  • Add and order multiple redaction profiles
  • Enable or disable individual profiles
  • Set the LLM codec
  • Edit builtin action settings such as action, target_paths, pattern, detector, replacement, and masking fields
  • Edit local.backend for a runtime-provided future local-model backend

The editor preserves unknown fields when it rewrites an existing pii_redaction component, so future or runtime-specific settings are not discarded by the interactive edit flow.

If your policy needs callback code instead of editor or configuration fields, use raw middleware.

Built-in Settings

The builtin section contains:

FieldPurpose
actionSanitization action. Current values are remove, redact, regex_replace, hash, and mask.
target_pathsExact JSON-pointer paths to sanitize. Empty means every matching string leaf.
patternRegex pattern used when action = "regex_replace" or action = "redact".
detectorOptional built-in matcher preset. Current values are email, phone, api_key, ip_address, ipv6, url, uuid, bearer_token, jwt, credit_card, aws_access_key_id, aws_secret_access_key, gcp_api_key, and azure_storage_account_key.
replacementReplacement text used when action = "regex_replace" or action = "redact". Defaults to [REDACTED].
mask_charMasking token used when action = "mask". Defaults to *.
unmasked_prefixLeading character count to keep when action = "mask". Defaults to 0, unless a detector-specific masking preset is active.
unmasked_suffixTrailing character count to keep when action = "mask". Defaults to 0, unless a detector-specific masking preset is active.

Action Semantics

remove

remove is structural.

When a target matches:

  • Object fields are removed.
  • Array elements become null.
  • Targeted scalar or root values become null.

regex_replace

regex_replace applies the configured regex to matching string leaves and replaces matches with the configured replacement.

If you set detector instead of pattern, the built-in backend uses the detector’s stock matcher regex.

redact

redact is the deterministic whole-match replacement lane.

It uses the same pattern or detector matcher flow as regex_replace, but defaults the replacement token to [REDACTED] and is intended for cases where you do not want to preserve any matched secret characters.

Use redact when you want:

  • credential-style secrets fully replaced
  • a consistent redaction token across detectors
  • clearer policy intent than a custom regex_replace

hash

hash replaces matching string leaves with their SHA-256 hex digest.

When pattern or detector is set, hash only replaces the matching substring instead of hashing the entire string leaf.

mask

mask replaces the middle portion of each matching string leaf with the configured mask_char.

Use unmasked_prefix and unmasked_suffix when you want to preserve a small leading or trailing segment for correlation or debugging, such as the last four characters of a token.

When pattern or detector is set, mask only masks matching substrings inside the string leaf.

When detector is set and you do not specify unmasked_prefix or unmasked_suffix, the built-in backend applies detector-aware defaults:

  • email: Preserves the domain and the first local-part character
  • phone: Preserves the last four digits while keeping separators intact
  • api_key: Preserves the vendor-style prefix such as sk- and the last four characters
  • ip_address: Preserves the last octet
  • ipv6: Preserves the last segment
  • url: Preserves the scheme and host, then collapses the path/query tail
  • uuid: Preserves the last four characters
  • bearer_token: Preserves the auth scheme and the last four characters
  • jwt: Preserves the header segment and the tail of the signature
  • credit_card: Preserves the last four digits while keeping separators intact
  • aws_access_key_id: Preserves the provider prefix and the last four characters
  • aws_secret_access_key: Preserves the last four characters
  • gcp_api_key: Preserves the AIza-style prefix and the last four characters
  • azure_storage_account_key: Preserves the last four characters

Path Semantics

target_paths are exact JSON-pointer matches.

The plugin uses different payload boundaries for tools and LLMs:

  • Tools use JSON-native payloads. Paths point into the emitted tool args or tool result shape directly.
  • LLMs use the selected built-in codec. Prefer normalized Relay paths such as:
    • /messages/0/content for request message content
    • /message for the normalized assistant response text
  • Marks and non-tool, non-LLM scopes sanitize data, category_profile, and metadata as separate JSON values. A target path is evaluated independently inside each value; it does not start with /data, /category_profile, or /metadata.

The current implementation also preserves provider-shaped response-path compatibility for the supported codecs, but normalized LLM paths are the recommended contract for new configuration.

Decision Rule

Use pii_redaction for reusable, config-driven privacy behavior. Use raw middleware when the policy depends on application-specific runtime state or custom callback logic. Refer to Plugin Versus Middleware for the full comparison.

Detector Presets

The built-in detector presets are grouped into three deterministic families:

Common PII

  • email
  • phone
  • ip_address
  • ipv6
  • url

Structured Secrets

  • api_key
  • uuid
  • bearer_token
  • jwt
  • credit_card

bearer_token is heuristic rather than vendor-specific. It can still match benign bearer-style values, so prefer a narrower detector when you know the credential family.

Cloud Credentials

  • aws_access_key_id
  • aws_secret_access_key
  • gcp_api_key
  • azure_storage_account_key

They are deterministic regex-backed helpers, not model inference.

If target_paths is empty, the built-in backend sanitizes every matching string leaf in the selected payload boundary.

Observability Semantics

The built-in plugin uses sanitize guardrails and event sanitizers.

That means:

  • The real provider request and response values are unchanged.
  • The emitted NeMo Relay start, end, or mark event observability fields are sanitized.
  • annotated_response is regenerated from the sanitized end-event payload when the configured response codec can decode that payload.
  • Subscribers and exporters consume only the sanitized canonical event stream. Each exporter can omit or transform fields as part of its normal projection, but raw values removed by the plugin do not bypass the sanitizer.

For tool and LLM scope events, the PII redaction scope sanitizer leaves data, category_profile, and metadata unchanged because the specialized tool or LLM sanitizer already owns that lifecycle boundary. This prevents repeated hashing or masking. Other scope categories use input for starts and output for ends.

Local Model Mode

local_model is reserved for a future in-process local-model backend.

Current Status

The current local-model status is:

  • The plugin contract accepts mode = "local_model".
  • The local section supports:
    • backend
    • model_id
    • detector_profile
    • allow_network
    • max_latency_ms
  • Actual behavior depends on a runtime-installed local backend provider.

Without a provider, runtimes report the local backend as unavailable during plugin initialization.