How the promptInjectionGuard in OmniRoute Protects Chat Completions from Injection Attacks

The promptInjectionGuard in OmniRoute intercepts malicious payloads before they reach LLM providers by evaluating request content against configurable regex patterns, aggregating severity scores, and either blocking the request with a 400 error or logging it based on the active guard mode.

OmniRoute is an open-source AI gateway that secures chat completion endpoints through a multi-layer defense system. The promptInjectionGuard serves as the primary barrier against adversarial prompt manipulation, processing every request through a sanitization pipeline before forwarding to upstream providers. This guardrail ensures that system-override directives and malformed injection patterns never compromise model behavior.

Middleware Entry Point and Request Wrapping

Every chat completion request first passes through the withInjectionGuard middleware defined in src/middleware/promptInjectionGuard.ts. This wrapper intercepts POST, PUT, and PATCH requests before they reach route handlers.

The middleware clones the incoming Request object, parses the JSON payload, and passes the parsed body to the guardrail evaluation function:

// src/middleware/promptInjectionGuard.ts
export const withInjectionGuard = (
  handler: RequestHandler,
  options?: GuardOptions
): RequestHandler => {
  return async (req, res) => {
    const body = await req.clone().json();
    const result = await guard(body, options);
    
    if (result.blocked) {
      return res.status(400).json({
        error: "Request blocked: potential prompt injection detected"
      });
    }
    return handler(req, res);
  };
};

When the guard returns { blocked: true }, the middleware immediately terminates the request with a 400 status code, preventing any downstream provider contact.

The Core Detection Pipeline

The actual detection logic resides in src/lib/guardrails/promptInjection.ts. The evaluatePromptInjection function orchestrates a multi-stage analysis pipeline:

  1. Initial Sanitization: The sanitizeRequest utility from src/shared/utils/inputSanitizer.ts performs first-pass regex checks against the payload, producing an initial set of detections.

  2. Pattern Scanning: The system normalizes default patterns (DEFAULT_GUARD_PATTERNS) and any user-supplied customPatterns using normalizePatternEntry, then scans the first 16 KB of joined message contents (bounded by MAX_INJECTION_SCAN_BYTES).

  3. Severity Aggregation: Detections are merged and flagged, with the overall severity compared against the configured block threshold via resolveBlockThreshold.

High-severity matches—such as system: override directives or malformed system blocks ( ```system)—trigger immediate escalation.

Configuration Modes and Feature Flags

The guard supports three operational modes determined by a hierarchical resolution chain:

  • Database feature flag: INJECTION_GUARD_MODE (defined in src/shared/constants/featureFlagDefinitions.ts)
  • Environment variable: INJECTION_GUARD_MODE or INPUT_SANITIZER_MODE
  • Default: "warn" mode

The resolution logic in src/lib/guardrails/promptInjection.ts reads:

const mode = (await getFeatureFlag('INJECTION_GUARD_MODE')) 
  ?? process.env.INJECTION_GUARD_MODE 
  ?? process.env.INPUT_SANITIZER_MODE 
  ?? 'warn';

The guard is enabled by default via the INPUT_SANITIZER_ENABLED environment variable (defaulting to true if absent). The three modes determine the enforcement level:

  • block: Rejects requests exceeding the severity threshold
  • warn: Allows the request but logs warnings
  • log: Allows the request with informational logging only

Blocking Behavior and Response Handling

When operating in block mode with a severity level above the configured threshold, the guard returns a blocking decision that propagates through the middleware stack. The chat completion route in src/app/api/v1/chat/completions/route.ts implements the same error path, ensuring consistent rejection behavior across endpoints.

The standard error response includes:

{
  "error": "Request blocked: potential prompt injection detected"
}

This response is generated both by the middleware wrapper and directly within route handlers that manually invoke the guard evaluation.

Practical Implementation Examples

Wrapping a Custom API Route

Apply the guard to specific endpoints with custom thresholds and patterns:

import { withInjectionGuard } from "@/middleware/promptInjectionGuard";
import { handler as chatHandler } from "./chatCore";

export default withInjectionGuard(chatHandler, {
  blockThreshold: "high",
  customPatterns: [/my_secret_keyword/i],
});

Configuring Tenant-Specific Mode via Database

Override the guard behavior for specific tenants using the feature flag system:

INSERT INTO feature_flags (name, value) 
VALUES ('INJECTION_GUARD_MODE', 'block');

This forces block mode for all requests belonging to that tenant, superseding environment variable configurations.

Manual Guard Evaluation

Access the guard's decision logic directly within business logic:

import { evaluatePromptInjection } from "@/lib/guardrails/promptInjection";

async function myEndpoint(req: Request) {
  const body = await req.json();
  const decision = evaluatePromptInjection(body, {}, { log: console });

  if (decision.blocked) {
    return new Response(
      JSON.stringify({ error: "Injection detected" }), 
      { status: 400 }
    );
  }
  
  // Proceed with normal processing
}

Summary

  • Pre-provider interception: The withInjectionGuard middleware in src/middleware/promptInjectionGuard.ts processes requests before they reach upstream LLM providers.
  • Multi-layer detection: The pipeline combines sanitizeRequest regex checks with normalized pattern scanning against the first 16 KB of message content.
  • Configurable enforcement: Modes (block, warn, log) are resolved via database feature flags INJECTION_GUARD_MODE, environment variables, or sensible defaults.
  • Immediate termination: Blocked requests receive a 400 status code with the message "Request blocked: potential prompt injection detected", preventing any provider forwarding.
  • Extensible patterns: Developers can supply customPatterns and adjust blockThreshold per endpoint or tenant.

Frequently Asked Questions

What types of prompt injection attacks does the guard detect?

The guard identifies system-override directives (e.g., system: override), malformed delimiter blocks ( ```system), and user-defined patterns. It scans the joined message contents using regex patterns from DEFAULT_GUARD_PATTERNS combined with any customPatterns provided during middleware initialization, evaluating against severity thresholds to distinguish between suspicious and benign inputs.

How do I configure the guard to block requests for one tenant while warning for others?

Set the INJECTION_GUARD_MODE feature flag in your database to 'block' for the specific tenant ID. The resolution logic in src/lib/guardrails/promptInjection.ts checks database flags before environment variables, allowing per-tenant overrides. For other tenants, omit the flag or set it to 'warn' to allow requests with logging.

What happens if the detection service fails or times out?

The guard defaults to enabled status (INPUT_SANITIZER_ENABLED defaults to true) and evaluates entirely within the request lifecycle without external service dependencies. If pattern matching or JSON parsing fails, the error propagates as a standard 400 or 500 response rather than silently allowing potentially malicious requests to pass through.

Can I use the promptInjectionGuard outside of chat completion routes?

Yes. The withInjectionGuard middleware and evaluatePromptInjection function are provider-agnostic. You can wrap any POST/PUT/PATCH handler or call the evaluation logic directly in custom endpoints, supplying options like customPatterns and blockThreshold to tailor detection for specific use cases beyond standard chat completions.

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 →