How OmniRoute's Guardrail System Prevents Prompt Injection and Credential Leakage

OmniRoute's guardrail system uses a hot-reloadable registry with preCall and postCall hooks to scan, redact, or block malicious content before it reaches upstream LLM providers.

The open-source OmniRoute project (diegosouzapw/OmniRoute) implements a layered defense architecture that intercepts every inbound request and outbound response. Its guardrail system combines pattern-based detection, configurable severity thresholds, and flexible deployment modes to stop prompt injection attacks and credential leakage without requiring code changes.


The Guardrail Registry: Core Architecture

At the heart of the system sits the guardrail registry (src/lib/guardrails/registry.ts). This module orchestrates a chain of guardrails that execute in priority order on every request/response cycle.

Each guardrail implements a standard interface with two lifecycle hooks:

  • preCall: Executes before the provider receives the request
  • postCall: Executes after the provider returns a response

The registry is fail-open by design—if a guardrail throws an exception, the error is logged and processing continues to the next guardrail. Traffic only blocks when a guardrail explicitly returns a block decision based on its own logic.

Guardrails can be globally enabled or disabled via environment variables, or overridden per-request using the x-omniroute-disabled-guardrails HTTP header.


Prompt Injection Prevention

The prompt injection guardrail (src/lib/guardrails/promptInjection.ts) protects upstream LLMs from malicious system prompt overrides and hidden instruction attacks.

Detection Components

Component Implementation
Pattern catalog Built-in DEFAULT_GUARD_PATTERNS with regexes like /system\s*:\s*override/i and markdown-embedded system prompt detection
Custom patterns User-defined regexes passed via customPatterns option
Severity scoring low, medium, or high classification per detection
Block threshold Configurable blockThreshold determines when rejection occurs
Operational modes "block" (reject), "warn" (log high-severity only), "log" (always log)

Execution Flow

The guardrail Processes requests through four stages:

  1. Sanitization: The payload runs through sanitizeRequest for baseline injection detection
  2. Pattern scanning: The first 16KB of concatenated message contents (MAX_INJECTION_SCAN_BYTES) is scanned against custom patterns
  3. Result merging: New detections merge with the sanitizer's findings
  4. Decision: If mode is "block" and accumulated severity exceeds blockThreshold, returns { block: true, message: "Request rejected: suspicious content detected" }; otherwise returns metadata describing detection counts

The default mode is "warn", overrideable via the INJECTION_GUARD_MODE feature flag using the precedence: database value > environment variable > default.


Credential Leakage Prevention

The credential masker guardrail (src/lib/guardrails/credentialMasker.ts) prevents accidental API key and secret token exposure to third-party LLM providers.

Key Mechanisms

Feature Description
Feature flag CREDENTIAL_REDACTION_ENABLED controls activation (DB > env > default)
Pattern matching Detects patterns like AWS keys (AKIA[0-9A-Z]{16}) and generic secrets ((?i)(secret|key)[\s:=]+[A-Za-z0-9+/=]{20,})
Redaction Matching substrings replaced with "⛔️[REDACTED]"
Metadata tracking Records redaction count in the payload meta

Hook Behavior

  • Pre-call: Returns modifiedPayload with redacted content—the provider never receives raw credentials
  • Post-call: Non-blocking; only records that redaction occurred

When disabled, the guardrail becomes a no-op with minimal performance overhead.


Complementary PII Protection

The PII masker guardrail (src/lib/guardrails/piiMasker.ts) extends protection to personally identifiable information. Enabled via PII_REDACTION_ENABLED, it traverses JSON payloads and applies processPII to every string value in both requests and responses.


End-to-End Request Flow


1. Incoming request
   └── guardrailRegistry.runPreCallHooks(payload, ctx)
       ├── credentialMasker (priority: highest)
       ├── piiMasker
       └── promptInjection (priority: lowest)
           ↓
2. If blocked → return 4xx error
   If passed → send modifiedPayload to provider
           ↓
3. Response received
   └── guardrailRegistry.runPostCallHooks(response, ctx)
       └── piiMasker (optional response redaction)

The /api/guardrails and /api/guardrails/test endpoints provide runtime observability into guardrail status and behavior.


Practical Configuration Examples

Per-Request Guardrail Disabling

For trusted internal services that need to send system prompts:

import { fetch } from "node-fetch";

await fetch("https://omniroute.example.com/v1/chat/completions", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-omniroute-disabled-guardrails": "prompt-injection",
  },
  body: JSON.stringify({
    model: "gpt-4o",
    messages: [{ role: "system", content: "You are a helpful assistant." }],
  }),
});

Environment-Based Configuration


# Enable strict prompt injection blocking

export INJECTION_GUARD_MODE=block

# Enable credential redaction

export CREDENTIAL_REDACTION_ENABLED=true

# Enable PII masking

export PII_REDACTION_ENABLED=true

Source File Reference

File Purpose
src/lib/guardrails/base.ts Abstract base class defining the guardrail interface
src/lib/guardrails/registry.ts Orchestrates guardrail execution order and hook invocation
src/lib/guardrails/promptInjection.ts Prompt injection detection (lines 49-85, 92-120, 162-184, 210-227, 248-267)
src/lib/guardrails/credentialMasker.ts API key and secret token redaction
src/lib/guardrails/piiMasker.ts Personal data identification and removal
docs/security/GUARDRAILS.md Architecture and configuration documentation

Summary

  • Hot-reloadable registry (src/lib/guardrails/registry.ts) chains guardrails with preCall and postCall hooks
  • Fail-open design logs errors but continues processing unless explicit block returned
  • Prompt injection guardrail uses DEFAULT_GUARD_PATTERNS, severity scoring, and configurable blockThreshold with INJECTION_GUARD_MODE control
  • Credential masker redacts secrets via CREDENTIAL_REDACTION_ENABLED before provider handoff
  • Per-request overrides supported via x-omniroute-disabled-guardrails header
  • Observable runtime through dedicated API endpoints

Frequently Asked Questions

What happens if a guardrail throws an exception?

The registry catches the error, logs it, and continues to the next guardrail. The system prioritizes availability over strict enforcement unless a guardrail explicitly returns a block decision.

Can I disable guardrails for specific requests only?

Yes. Pass the x-omniroute-disabled-guardrails header with a comma-separated list of guardrail names to disable. This is useful for trusted internal services that need to send system prompts or handle pre-validated data.

How does the prompt injection guardrail handle large payloads?

It limits scanning to the first 16KB of concatenated message contents (MAX_INJECTION_SCAN_BYTES). This balances security coverage with performance, as injection attempts typically appear in early message content.

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 →