How OmniRoute Guardrails Enable Opt-In PII Redaction with PII-Masker and Prompt-Injection Detection

OmniRoute uses a pluggable guardrail framework that inspects and modifies request payloads and responses through two specialized guardrails: PII-Masker for opt-in personal data redaction and Prompt-Injection for malicious directive detection.

The open-source OmniRoute repository (diegosouzapw/OmniRoute) provides a security layer that processes every LLM request through configurable guardrails. These components run at specific pipeline stages to ensure personal information remains protected and malicious inputs are blocked before reaching upstream providers.

Understanding OmniRoute's Guardrail Architecture

OmniRoute implements a registry-based guardrail system where each guardrail extends a base class and registers itself for execution. The framework supports two primary lifecycle hooks: pre-call (before sending to the LLM provider) and post-call (after receiving the response).

The PII-Masker guardrail operates in both stages, sanitizing sensitive data from incoming requests and redacting any PII that appears in provider responses. The Prompt-Injection guardrail runs exclusively during the pre-call phase, scanning for malicious patterns like system_override_inline or markdown_system_block directives.

According to the source code in src/lib/guardrails/base.ts, all guardrails extend the abstract BaseGuardrail class, while src/lib/guardrails/registry.ts provides the GuardrailRegistry that orchestrates registration and sequential execution.

How the PII-Masker Guardrail Implements Opt-In Redaction

The PII-Masker guardrail follows a strict opt-in model, requiring explicit environment configuration before activating redaction features. This ensures that data masking only occurs when operators intentionally enable it.

Configuration and Enablement Checks

The guardrail checks activation status through isRequestPiiMaskingEnabled() in src/lib/guardrails/piiMasker.ts (lines 12-16). This function returns true only when both environment variables are set:

  • PII_REDACTION_ENABLED="true"
  • INPUT_SANITIZER_MODE="redact"

If either condition fails, the guardrail returns the original payload unchanged, satisfying OmniRoute's requirement that PII redaction must be explicitly opted into rather than enabled by default.

Request-Side PII Sanitization

When enabled, the cloneAndMaskRequestPayload() function creates a deep clone of the request and walks through system, messages, and input fields. For each string value encountered, it calls sanitizeStringValue(), which utilizes the shared processPII() utility from src/shared/utils/inputSanitizer.ts.

Detected PII entities accumulate in a detections array (lines 30-38 of piiMasker.ts). If modifications occur, the guardrail returns a modifiedPayload alongside metadata indicating the detection count and a redacted: true flag (lines 71-86).

Response-Side PII Redaction

The post-call stage executes sanitizePIIResponse() from src/lib/piiSanitizer.ts, targeting the top-level output_text field and nested output arrays. The helper maskResponsesOutput() traverses content structures up to 16 KB and replaces detected PII with redacted markers (lines 31-57).

Even when request-side masking is disabled, this post-call sanitization runs automatically to prevent PII leakage in LLM responses. The guardrail returns modifiedResponse only when the response shape differs from the original (lines 98-105).

How the Prompt-Injection Guardrail Protects LLM Requests

The Prompt-Injection guardrail provides active protection against jailbreak attempts and system prompt leaks through pattern matching and severity-based blocking.

Mode Resolution and Pattern Matching

Configuration resolution occurs in src/lib/guardrails/promptInjection.ts through the getMode() method (lines 34-52). The system checks the database feature-flag INJECTION_GUARD_MODE first, then falls back to environment variables INJECTION_GUARD_MODE and INPUT_SANITIZER_MODE, defaulting to "warn" mode.

Default high-severity patterns defined in DEFAULT_GUARD_PATTERNS (lines 42-53) include detection rules for system_override_inline and markdown_system_block attacks. Custom patterns supplied via the constructor are normalized by normalizePatternEntry() to a unified {name, pattern, severity} structure (lines 61-86).

Detection and Blocking Logic

The sanitizeRequest() function extracts message contents via extractMessageContents() and scans up to MAX_INJECTION_SCAN_BYTES (16 KB) using detectWithPatterns() (lines 90-99).

The shouldBlock() method (lines 20-27) compares detection severities against the configured threshold (defaulting to "high"). When the guardrail operates in "block" mode and detects a qualifying threat, it rejects the request immediately. In "warn" or "log" modes, the request proceeds but emits detailed logging entries (lines 30-44).

The final GuardrailResult object contains a block boolean and metadata about detection counts (lines 60-82).

Enabling and Configuring Guardrails

Activate PII redaction by setting the required environment variables:


# .env configuration

PII_REDACTION_ENABLED=true
INPUT_SANITIZER_MODE=redact

Register guardrails programmatically with custom injection patterns:

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: [/evil-command/i],
  })
);

Inspect guardrail execution results to determine if modifications or blocks occurred:

const result = await guardrailRegistry.runPreCall(payload, {});
if (result.block) {
  console.error("Request blocked:", result.message);
} else if (result.modifiedPayload) {
  console.log("Payload was redacted:", result.modifiedPayload);
}

Summary

  • Opt-in by design: PII-Masker requires explicit PII_REDACTION_ENABLED and INPUT_SANITIZER_MODE environment variables to activate redaction features.
  • Dual-stage protection: PII-Masker sanitizes request payloads pre-call and redacts sensitive data from LLM responses post-call via sanitizePIIResponse().
  • Configurable injection detection: Prompt-Injection guardrail supports block, warn, and log modes controlled through database feature-flags or environment variables.
  • Pattern extensibility: Both guardrails accept custom detection patterns, with Prompt-Injection supporting severity thresholds and regex-based rules.
  • Registry architecture: The GuardrailRegistry in src/lib/guardrails/registry.ts orchestrates multiple guardrails, returning unified results containing block decisions and modification metadata.

Frequently Asked Questions

Is PII redaction enabled by default in OmniRoute?

No, PII redaction is strictly opt-in. The isRequestPiiMaskingEnabled() function in src/lib/guardrails/piiMasker.ts returns false unless both PII_REDACTION_ENABLED is set to "true" and INPUT_SANITIZER_MODE equals "redact". Without these explicit configurations, the guardrail passes payloads through unchanged.

Can I use custom patterns for prompt injection detection?

Yes, the Prompt-Injection guardrail accepts custom patterns via its constructor options. Pass an array of regex patterns or pattern objects to customPatterns, and the normalizePatternEntry() function will normalize them to the standard {name, pattern, severity} format. These patterns are scanned alongside default high-severity patterns like system_override_inline.

What happens if PII is detected in the LLM response?

Even when request-side masking is disabled, the post-call stage in piiMasker.ts executes sanitizePIIResponse() to scan the provider's output. If PII appears in output_text or nested content structures within the output array, the maskResponsesOutput() helper redacts the sensitive data and returns a modifiedResponse flagged with redaction metadata.

How does the guardrail registry orchestrate multiple guardrails?

The GuardrailRegistry class maintains a collection of guardrail instances and executes them sequentially during pre-call and post-call phases. For pre-call processing, it runs runPreCall() which aggregates results from all registered guardrails, determining if any guardrail blocks the request or modifies the payload. The registry returns a unified GuardrailResult containing combined metadata from all executed guardrails.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →