# How OmniRoute Guardrails Work with Opt-In PII Redaction: PII-Masker and Prompt-Injection Deep Dive

> Understand OmniRoute guardrails like PII-masker and prompt-injection with opt-in PII redaction. Secure sensitive data in LLM requests and responses.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: deep-dive
- Published: 2026-07-30

---

**OmniRoute's pluggable guardrail framework inspects LLM request payloads and responses at pre-call and post-call stages, strictly requiring explicit environment variable configuration to enable PII redaction while running prompt-injection detection by default with configurable blocking modes.**

OmniRoute (diegosouzapw/OmniRoute) implements a modular security layer through abstract guardrails that intercept traffic before it reaches upstream providers and after responses return. This architecture ensures that sensitive data handling remains under operator control, with PII masking defaulting to disabled unless specifically activated via environment variables. The framework centers on the `BaseGuardrail` class in [`src/lib/guardrails/base.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/base.ts) and the `GuardrailRegistry` orchestrator in [`src/lib/guardrails/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/registry.ts), which together manage the execution pipeline for all active guardrails.

## Understanding the PII-Masker Guardrail Architecture

The **PII-Masker guardrail** ([`src/lib/guardrails/piiMasker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/piiMasker.ts)) operates bidirectionally, scanning both incoming requests and outgoing responses for personally identifiable information. Unlike the prompt-injection guardrail, PII redaction follows a strict opt-in model governed by multiple configuration checks.

### Activation Requirements and Environment Checks

Before modifying any payload, the guardrail validates configuration through `isRequestPiiMaskingEnabled()` (lines 12-16). This function returns `true` only when both `PII_REDACTION_ENABLED` equals `"true"` and `INPUT_SANITIZER_MODE` equals `"redact"`. The dual-variable requirement ensures operators cannot accidentally enable redaction through a single misconfiguration.

```bash

# Required environment variables to enable request-side PII redaction

PII_REDACTION_ENABLED=true
INPUT_SANITIZER_MODE=redact

```

### Request-Side Sanitization Pipeline

When enabled, `cloneAndMaskRequestPayload()` performs a deep clone of the request payload and traverses `system`, `messages`, and `input` fields (lines 30-38). For each string value encountered, it invokes `sanitizeStringValue()`, which delegates to `processPII()` from [`src/shared/utils/inputSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/inputSanitizer.ts). This utility returns detected PII entities alongside redacted text, accumulating findings in a `detections` array. If modifications occur, the guardrail returns a `modifiedPayload` with metadata containing the detection count and a `redacted: true` flag (lines 71-86).

### Response Content Protection

The post-call stage runs `sanitizePIIResponse()` from [`src/lib/piiSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/piiSanitizer.ts) (lines 28-61), ensuring that PII potentially introduced by the LLM provider never reaches the client. The helper `maskResponsesOutput()` walks nested `content` structures within the response's `output` array, applying redaction to any detected personal data (lines 31-57). The guardrail returns `modifiedResponse` only when the response shape differs from the original (lines 98-105), maintaining performance by avoiding unnecessary object creation when no PII is present.

## How the Prompt-Injection Guardrail Secures Requests

The **Prompt-Injection guardrail** ([`src/lib/guardrails/promptInjection.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/promptInjection.ts)) focuses exclusively on the pre-call stage, analyzing request messages for malicious directives such as system prompt overrides or markdown injection attacks.

### Configuration Hierarchy and Mode Resolution

The guardrail resolves its operational mode through a prioritized cascade in `getMode()` (lines 34-52). First, it checks the database feature-flag `INJECTION_GUARD_MODE` via `getFeatureFlagOverride` in [`src/lib/db/featureFlags.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/featureFlags.ts). If unset, it falls back to the `INJECTION_GUARD_MODE` environment variable, then `INPUT_SANITIZER_MODE`, defaulting to `"warn"` if none are configured. Meanwhile, `isEnabled()` (line 59) respects the `INPUT_SANITIZER_ENABLED` environment variable, allowing complete deactivation when set to `"false"`.

### Pattern Detection and Scanning Logic

Default detection patterns defined in `DEFAULT_GUARD_PATTERNS` (lines 42-53) include high-severity signatures like `system_override_inline` and `markdown_system_block`. Custom patterns supplied through the constructor undergo normalization via `normalizePatternEntry()` to a unified `{name, pattern, severity}` structure (lines 61-86).

During execution, `sanitizeRequest()` extracts built-in detections while `extractMessageContents()` isolates raw message text. The guardrail scans up to **16 KB** (`MAX_INJECTION_SCAN_BYTES`) of content using `detectWithPatterns()` (lines 90-99), ensuring performance remains predictable for large payloads.

### Decision Logic and Blocking Behavior

The `shouldBlock()` function compares detection severities against the configured threshold (defaulting to `high`) (lines 20-27). When operating in `"block"` mode with matching severity, the request is rejected immediately. In `"warn"` or `"log"` modes, the request proceeds but generates audit entries (lines 30-44). The final `GuardrailResult` object contains `block: true/false` alongside metadata detailing detection counts (lines 60-82).

## Configuring Guardrails in Production

You can programmatically extend the guardrail system with custom injection patterns while respecting the opt-in PII requirements:

```typescript
import { GuardrailRegistry } from "@/lib/guardrails/registry";
import { PromptInjectionGuardrail } from "@/lib/guardrails/promptInjection";

const registry = new GuardrailRegistry();
registry.register(
  new PromptInjectionGuardrail({
    mode: "block",
    blockThreshold: "high",
    customPatterns: [/override-system-prompt/i],
  })
);

```

Inspect guardrail execution results to determine if modifications occurred:

```typescript
const result = await guardrailRegistry.runPreCall(payload, {});
if (result.block) {
  console.error("Request blocked:", result.message);
} else if (result.modifiedPayload) {
  console.log("PII redaction applied:", result.modifiedPayload);
}

```

## Summary

- **Strict opt-in model**: PII redaction requires both `PII_REDACTION_ENABLED=true` and `INPUT_SANITIZER_MODE=redact` environment variables, ensuring no accidental data masking occurs.
- **Bidirectional protection**: The PII-Masker guardrail sanitizes request payloads pre-call and response content post-call through `sanitizePIIResponse()` and `maskResponsesOutput()`.
- **Hierarchical configuration**: Prompt-Injection guardrail modes resolve through database feature flags first, then environment variables, supporting dynamic policy changes without deployment.
- **Performance boundaries**: Injection scanning limits input to 16KB (`MAX_INJECTION_SCAN_BYTES`) and short-circuits response processing when no modifications are detected.

## Frequently Asked Questions

### How does OmniRoute ensure PII redaction remains opt-in by default?

OmniRoute implements a dual-environment-variable gate in [`src/lib/guardrails/piiMasker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/piiMasker.ts) where `isRequestPiiMaskingEnabled()` checks for both `PII_REDACTION_ENABLED="true"` and `INPUT_SANITIZER_MODE="redact"`. Even when the guardrail is registered in the pipeline, it returns the original payload unchanged unless both conditions are satisfied, preventing accidental activation through single-variable misconfiguration.

### Can the Prompt-Injection guardrail block requests while allowing PII redaction to remain disabled?

Yes. These systems operate independently. The Prompt-Injection guardrail defaults to active unless `INPUT_SANITIZER_ENABLED="false"` is set, while PII redaction requires explicit opt-in via `PII_REDACTION_ENABLED`. You can configure `INJECTION_GUARD_MODE=block` to reject malicious prompts while keeping `PII_REDACTION_ENABLED` undefined to pass legitimate payloads through without modification.

### Where does OmniRoute look for prompt-injection patterns beyond the defaults?

Beyond `DEFAULT_GUARD_PATTERNS` defined in [`src/lib/guardrails/promptInjection.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/promptInjection.ts) (lines 42-53), operators can supply custom regex patterns through the guardrail constructor. These undergo normalization via `normalizePatternEntry()` (lines 61-86) to ensure uniform `{name, pattern, severity}` objects before scanning occurs in `detectWithPatterns()`.

### What happens if PII appears in an LLM response when request-side redaction was disabled?

The PII-Masker's `postCall()` method runs regardless of request-side configuration (lines 73-106 in [`src/lib/guardrails/piiMasker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/piiMasker.ts)). It invokes `sanitizePIIResponse()` from [`src/lib/piiSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/piiSanitizer.ts), which redacts any detected PII in the `output_text` and nested `content` fields before the response reaches the client. This ensures that even if PII bypasses request filters or is generated by the model, it is sanitized before transmission.