How to Implement Guardrails in OmniRoute: PII Redaction, Prompt Injection Detection, and Vision Safety

OmniRoute provides a modular guardrail framework that intercepts LLM requests and responses to enforce PII redaction, detect prompt injection attacks, and validate vision inputs through configurable pre-call and post-call hooks.

The open-source OmniRoute repository (`diegosouzapw/OmniRoute) ships with a production-ready guardrail system designed to secure AI applications without modifying core routing logic. By implementing guardrails in OmniRoute, developers can sanitize sensitive data, block adversarial prompts, and enforce safety policies on vision-enabled models through a unified pipeline architecture.

Understanding the OmniRoute Guardrail Architecture

All guardrails in OmniRoute inherit from BaseGuardrail defined in src/lib/guardrails/base.ts. This abstract class establishes a consistent interface where every guardrail implements preCall (request intercept) and postCall (response intercept) methods.

The guardrail pipeline orchestrates execution through src/lib/guardrails/index.ts. When a request arrives at the API route, the pipeline iterates over registered guardrails from src/lib/guardrails/registry.ts:

  1. Pre-call phase: Each guardrail's preCall method executes sequentially. If any guardrail returns { block: true }, the request aborts immediately with an error response.
  2. Provider execution: If all pre-call checks pass, the request proceeds to the underlying LLM provider.
  3. Post-call phase: After receiving the model response, the pipeline invokes each guardrail's postCall method to sanitize outputs before returning them to the client.

Guardrails are ordered by priority in the registry, allowing high-priority safety checks (like PII masking) to run before lower-priority transformations.

Implementing PII Redaction in OmniRoute

The PII Masker guardrail (src/lib/guardrails/piiMasker.ts) automatically redacts personally identifiable information from both inbound requests and outbound responses.

How PII Redaction Works

The guardrail inspects string fields across the payload—including system, messages, prompt, and input—using the cloneAndMaskRequestPayload function. It delegates actual redaction to processPII from shared/utils/inputSanitizer, controlled by the isRequestPiiMaskingEnabled() feature flag.

On the response side, maskResponsesOutput walks through fields like output_text and output[].content[].text to sanitize any PII that may have leaked from the model.

Enabling PII Protection

Set the environment variable in your .env configuration:

PII_REDACTION_ENABLED=true

When disabled, the guardrail performs a no-op to maintain backward compatibility while remaining in the pipeline.

Usage Example

import { PIIMaskerGuardrail } from '@/lib/guardrails/piiMasker';

const piiGuard = new PIIMaskerGuardrail({ enabled: true });

// Before sending to the model
const preResult = await piiGuard.preCall(requestBody, context);
if (preResult.modifiedPayload) {
  requestBody = preResult.modifiedPayload;
}

// After receiving the model response
const postResult = await piiGuard.postCall(modelResponse, context);
if (postResult.modifiedResponse) {
  modelResponse = postResult.modifiedResponse;
}

Configuring Prompt Injection Detection

The Prompt Injection Guardrail (src/lib/guardrails/promptInjection.ts) identifies malicious prompt injection attempts using built-in patterns and customizable detection rules.

Detection Logic

The evaluatePromptInjection function orchestrates the validation flow:

  1. Content extraction: extractMessageContents retrieves raw text from the request payload.
  2. Pattern matching: detectWithPatterns scans the first 16KB of joined message contents against built-in sanitization rules and any customPatterns provided in the configuration.
  3. Severity scoring: Detections are scored using SHARED_SEVERITY_SCORES.
  4. Action decision: shouldBlock compares detection severities against the configured blockThreshold to determine if the request should be rejected.

Configuration Options

import { PromptInjectionGuardrail } from '@/lib/guardrails/promptInjection';

const injectionGuard = new PromptInjectionGuardrail({
  enabled: true,
  mode: 'block',           // Options: 'warn', 'log', or 'block'
  blockThreshold: 'high',    // Block only when severity ≥ high
  customPatterns: [
    { 
      name: 'dangerous_sql', 
      pattern: /select\s+.*\s+from\s+/, 
      severity: 'high' 
    },
  ],
});

The guardrail respects the INPUT_SANITIZER_ENABLED feature flag and supports runtime overrides via INJECTION_GUARD_MODE environment variables or database configurations.

Securing Vision Models with Vision Bridge Guardrails

OmniRoute protects vision-enabled endpoints through the Vision Bridge guardrail system, defined in src/lib/guardrails/visionBridge.ts and supporting files.

Safety Validation Layers

The Vision Bridge performs four critical safety checks:

  • Image validation: Rejects unsupported formats or oversized blobs before they reach the provider.
  • Credential verification: Ensures API keys or OAuth tokens are present and correctly resolved via resolvePublicCred from visionBridgeCredentials.ts.
  • Rate limiting: Integrates with the global connection-cooldown mechanism to prevent endpoint hammering.
  • Output sanitization: Passes vision model responses through the PII masker to prevent data leakage.

Implementation Structure

The Vision Bridge spans multiple specialized files:

File Purpose
visionBridge.ts Core guardrail validating image inputs and orchestrating vision model execution
visionBridgeHelpers.ts Utilities for extracting image parts and converting them to data-URIs
visionBridgeCredentials.ts Secure credential handling and secret resolution
visionBridgeRouter.ts Routes vision requests through guardrails and executors

Integration Example

import { VisionBridgeGuardrail } from '@/lib/guardrails/visionBridge';

const visionGuard = new VisionBridgeGuardrail({
  enabled: true,
  priority: 15,  // Execute after PII masking but before routing
});

// Validate image payload before execution
await visionGuard.preCall(imagePayload, context);
const result = await visionExecutor.execute(imagePayload);
// Sanitize vision model output
await visionGuard.postCall(result, context);

Creating a Custom Guardrail Pipeline

To implement guardrails in OmniRoute for production workloads, assemble the complete pipeline using the guardrail registry pattern:

import { GuardrailContext } from '@/lib/guardrails/base';
import { PIIMaskerGuardrail } from '@/lib/guardrails/piiMasker';
import { PromptInjectionGuardrail } from '@/lib/guardrails/promptInjection';
import { VisionBridgeGuardrail } from '@/lib/guardrails/visionBridge';

// Initialize guardrails in priority order
const guardrails = [
  new PIIMaskerGuardrail({ enabled: true }),
  new PromptInjectionGuardrail({ 
    mode: 'warn', 
    blockThreshold: 'medium' 
  }),
  new VisionBridgeGuardrail({ enabled: true }),
];

async function processLlmRequest(payload: unknown) {
  const context: GuardrailContext = { log: console };
  
  // Pre-call phase: PII masking and injection detection
  for (const guardrail of guardrails) {
    const result = await guardrail.preCall(payload, context);
    if (result.block) {
      throw new Error(result.message ?? 'Blocked by guardrail');
    }
    if (result.modifiedPayload) {
      payload = result.modifiedPayload;
    }
  }
  
  // Execute against LLM provider
  let response = await llmProvider.execute(payload);
  
  // Post-call phase: Sanitize outputs
  for (const guardrail of guardrails) {
    const result = await guardrail.postCall(response, context);
    if (result.modifiedResponse) {
      response = result.modifiedResponse;
    }
  }
  
  return response;
}

Register new guardrails in src/lib/guardrails/registry.ts by extending BaseGuardrail and exporting the class in src/lib/guardrails/index.ts. The registry automatically builds the ordered list based on each guardrail's priority property.

Summary

  • Architectural foundation: Guardrails in OmniRoute extend BaseGuardrail and implement preCall/postCall methods orchestrated by the pipeline in src/lib/guardrails/index.ts.
  • PII protection: Enable via PII_REDACTION_ENABLED to automatically sanitize requests through cloneAndMaskRequestPayload and responses through maskResponsesOutput in piiMasker.ts.
  • Injection defense: Configure PromptInjectionGuardrail with custom patterns and severity thresholds; the evaluatePromptInjection function handles detection across the first 16KB of message content.
  • Vision safety: The Vision Bridge validates images, resolves credentials securely, and enforces rate limits before executing vision models.
  • Extensibility: Add custom guardrails by implementing the base interface and registering them in registry.ts with appropriate priority values.

Frequently Asked Questions

How do I enable PII redaction without blocking legitimate requests?

Set PII_REDACTION_ENABLED=true in your environment variables. The PIIMaskerGuardrail automatically replaces detected PII with redacted tokens while allowing the sanitized request to proceed. The guardrail performs masking rather than blocking, ensuring that legitimate traffic containing accidental PII (like user signatures) is cleaned without service interruption.

Can I use custom regex patterns for prompt injection detection?

Yes. Pass a customPatterns array when instantiating PromptInjectionGuardrail. Each pattern object requires name, pattern (RegExp), and severity properties. The detectWithPatterns function merges these with built-in patterns and scans the first 16KB of request content, allowing you to detect domain-specific injection attempts alongside OmniRoute's default protections.

What happens when a guardrail blocks a request?

When any guardrail's preCall method returns { block: true }, the pipeline immediately aborts and returns an error response to the client without reaching the LLM provider. For the prompt injection guardrail specifically, you can configure the mode parameter as 'warn' (log only), 'log' (structured logging), or 'block' (reject request) to control the behavior when shouldBlock determines the severity meets the threshold.

How does the Vision Bridge handle authentication credentials?

The Vision Bridge uses visionBridgeCredentials.ts to manage provider-specific secrets. It calls resolvePublicCred to safely retrieve API keys or OAuth tokens from environment variables or secure vaults, ensuring credentials are validated before the image payload is forwarded to vision models like Gemini Vision or Claude Vision. This prevents unauthorized access while maintaining clean separation between routing logic and secret management.

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 →