# OmniRoute Guardrails Configuration: How to Secure PII, Block Prompt Injection, and Enable Vision Bridging

> Configure OmniRoute guardrails like PII-masker, prompt-injection, and vision-bridge via the centralized registry. Secure your data and enhance your application with simple environment variable or database settings.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: how-to-guide
- Published: 2026-07-08

---

**OmniRoute's guardrails are configured through the centralized registry in [`src/lib/guardrails/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/registry.ts), where each guardrail—PII-masker, prompt-injection, and vision-bridge—extends `BaseGuardrail` and implements `preCall` and `postCall` methods controlled via environment variables, database settings, and per-request headers.**

The OmniRoute routing engine ships with a built-in guardrail framework that intercepts requests before they reach upstream providers and sanitizes responses before they return to clients. These guardrails are registered at server startup and consulted by the chat handler pipeline, providing configurable protection against data leakage, malicious inputs, and incompatible vision payloads. Understanding how to configure each guardrail ensures you can enforce security policies without compromising routing performance.

## Understanding the Guardrail Architecture

All guardrails in OmniRoute inherit from a common abstract class and are managed through a singleton registry pattern.

### The BaseGuardrail Abstract Class

Every guardrail extends the `BaseGuardrail` class defined in [`src/lib/guardrails/base.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/base.ts). This contract requires implementations to provide:

- **`preCall(payload, context)`**: Executed before the request is forwarded to the model provider; can modify the payload or block the request.
- **`postCall(response, context)`**: Executed after receiving the upstream response; can modify the response content.
- **Priority levels**: Lower numbers execute earlier (e.g., PII-masker uses `priority: 10`, vision-bridge uses `priority: 5`).

Both methods return a `GuardrailResult` object containing `block` (boolean), `modifiedPayload` or `modifiedResponse`, and metadata for observability.

### The Centralized Registry

The `guardrailRegistry` singleton in [`src/lib/guardrails/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/registry.ts) maintains the ordered list of active guardrails. During server initialization in [`src/server-init.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server-init.ts), the function `registerDefaultGuardrails()` instantiates the three built-in guardrails and inserts them into the registry. The chat handler in [`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts) iterates over this registry for every request, executing `preCall` methods sequentially until a block occurs or all guardrails complete.

## Configuring the PII-Masker Guardrail

The **PII-masker** guardrail redacts personally identifiable information from both requests and responses before they leave the OmniRoute infrastructure.

### Implementation Details

Located in [`src/lib/guardrails/piiMasker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/piiMasker.ts), the `PIIMaskerGuardrail` class implements:

- **Request-side masking**: The `cloneAndMaskRequestPayload()` function walks the JSON payload recursively, applying `sanitizePII()` from [`src/lib/piiSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/piiSanitizer.ts) to every string value.
- **Response-side masking**: The `maskResponsesOutput()` method sanitizes the `output_text` and `output` fields using `sanitizePIIResponse()` before streaming to the client.

```typescript
// src/lib/guardrails/piiMasker.ts
export class PIIMaskerGuardrail extends BaseGuardrail {
  async preCall(payload, _context) {
    const result = cloneAndMaskRequestPayload(payload);
    return { block: false, modifiedPayload: result.payload };
  }

  async postCall(response, _context) {
    // sanitizes response fields
    return { block: false, modifiedResponse: sanitized };
  }
}

```

### Configuration Options

Enable or disable PII redaction through these mechanisms:

- **Environment variable**: Set `PII_REDACTION_ENABLED=true` to activate the guardrail globally.
- **Mode configuration**: Use `INPUT_SANITIZER_MODE=redact` to specify redaction behavior (as opposed to other sanitization modes).
- **Default state**: The guardrail is **enabled by default** with `priority: 10`, ensuring it runs early in the pre-call chain.

## Configuring the Prompt-Injection Guardrail

The **prompt-injection** guardrail detects malicious system-override attempts and other injection patterns in user inputs.

### Detection Logic

The core detection routine `evaluatePromptInjection()` in [`src/lib/guardrails/promptInjection.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/promptInjection.ts) performs the following steps:

1. Sanitizes the payload using `sanitizeRequest()` from [`src/shared/utils/inputSanitizer.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/utils/inputSanitizer.ts).
2. Extracts raw message text via `extractMessageContents()`.
3. Scans the first 16 KB (`MAX_INJECTION_SCAN_BYTES`) of content for patterns matching `DEFAULT_GUARD_PATTERNS` or custom patterns supplied via `options.customPatterns`.
4. Aggregates severity scores and compares against the configured `blockThreshold`.

```typescript
// src/lib/guardrails/promptInjection.ts
export function evaluatePromptInjection(body, options = {}, context = {}) {
  const scanText = joinedContents.slice(0, MAX_INJECTION_SCAN_BYTES);
  const customDetections = detectWithPatterns(scanText, patterns);
  // Merges detections and determines block/warn/log action
}

```

The `PromptInjectionGuardrail` class wraps this logic, returning a block result when the threshold is exceeded.

### Mode and Threshold Settings

Configure the guardrail's behavior through these parameters:

| Option | Default | Configuration Source |
|--------|---------|---------------------|
| `mode` | `"warn"` | Environment variable `INJECTION_GUARD_MODE` or database flag |
| `blockThreshold` | `"high"` | `getThreshold()` function |
| `enabled` | `true` | `INPUT_SANITIZER_ENABLED` environment variable |

**Available modes**:
- **`block`**: Rejects the request with a 400-level error when patterns exceed the threshold.
- **`warn`**: Allows the request but logs the detection.
- **`log`**: Silently records detections without modifying the request flow.

### Disabling Per Request

Send the header `x-omniroute-disabled-guardrails: prompt-injection` to bypass the guardrail for specific requests. The registry checks this header in [`src/lib/guardrails/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/registry.ts) before executing any guardrail's `preCall` method.

## Configuring the Vision-Bridge Guardrail

The **vision-bridge** guardrail enables non-vision models to process image inputs by converting images to text descriptions using a configured vision model.

### How It Works

The `VisionBridgeGuardrail` in [`src/lib/guardrails/visionBridge.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/visionBridge.ts) uses `getComboVisionBridgeDecision()` to analyze routing tables and determine if the selected model lacks vision capabilities. If all targets support vision, the guardrail skips processing to minimize latency.

When images require processing:

1. Extracts image parts via `extractImageParts()` from [`src/lib/guardrails/visionBridgeHelpers.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/visionBridgeHelpers.ts).
2. Limits concurrent images to the configured `maxImages` setting.
3. Calls the vision model via `callVisionModel()` for each image in parallel using `Promise.allSettled`.
4. Replaces image blocks with textual descriptions using `replaceImageParts()`.

```typescript
// src/lib/guardrails/visionBridge.ts
if (imageParts.length === 0) return { block: false };
const results = await Promise.allSettled(
  limitedParts.map(async (p, i) => {
    const desc = await callVision(p.imageUrl, config);
    return `[Image ${i + 1}]: ${desc}`;
  })
);
return { block: false, modifiedPayload: modifiedBody, meta: { processed: results.length } };

```

### Configuration Sources

- **Database settings**: Flags stored in [`src/lib/db/settings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/settings.ts) control global enablement.
- **Defaults**: Constants in [`src/shared/constants/visionBridgeDefaults.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/visionBridgeDefaults.ts) define `maxImages` and timeout values.
- **Priority**: Executes with `priority: 5`, running before the PII-masker but after any higher-priority custom guardrails.
- **Disable header**: Use `x-omniroute-disabled-guardrails: vision-bridge` to skip processing for specific requests.

## Integrating Guardrails into the Request Lifecycle

Guardrails are wired into the request flow through explicit registration and handler integration.

### Server Initialization

In [`src/server-init.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/server-init.ts), the following code loads guardrails at startup:

```typescript
// src/server-init.ts
import { registerDefaultGuardrails } from "./lib/guardrails";
registerDefaultGuardrails();

```

This function instantiates the PII-masker, prompt-injection, and vision-bridge guardrails and inserts them into the singleton registry.

### Pipeline Execution

The chat handler in [`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts) executes guardrails in two phases:

**Pre-call phase**:

```typescript
// src/sse/handlers/chat.ts
for (const guardrail of guardrailRegistry.list()) {
  const result = await guardrail.preCall(payload, context);
  if (result.block) return earlyResponse(result);
  if (result.modifiedPayload) payload = result.modifiedPayload;
}

```

**Post-call phase**:
After receiving the upstream response, the handler iterates through guardrails again, applying `postCall()` methods (notably the PII-masker) to sanitize output before streaming to the client.

### Practical Configuration Examples

**Disable prompt-injection for a single request**:

```bash
curl -X POST http://localhost:3000/api/chat/completions \
  -H "Content-Type: application/json" \
  -H "x-omniroute-disabled-guardrails: prompt-injection" \
  -d '{"model": "gpt-4", "messages": [{"role": "user", "content": "Test"}]}'

```

**Send an image through a non-vision model** (automatically triggers vision-bridge):

```typescript
await fetch("/api/chat/completions", {
  method: "POST",
  body: JSON.stringify({
    model: "gpt-4o-mini",
    messages: [{
      role: "user",
      content: [{ type: "image_url", image_url: { url: "data:image/png;base64,..." } }]
    }]
  })
});

```

## Summary

- **OmniRoute guardrails** extend `BaseGuardrail` in [`src/lib/guardrails/base.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/base.ts) and register via [`src/lib/guardrails/registry.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/registry.ts) to process requests in priority order.
- **PII-masker** ([`src/lib/guardrails/piiMasker.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/piiMasker.ts)) is controlled by `PII_REDACTION_ENABLED` and runs at priority 10 to sanitize both requests and responses.
- **Prompt-injection** ([`src/lib/guardrails/promptInjection.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/promptInjection.ts)) scans the first 16 KB of input using `evaluatePromptInjection()`, supporting `block`, `warn`, and `log` modes via `INJECTION_GUARD_MODE`.
- **Vision-bridge** ([`src/lib/guardrails/visionBridge.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/visionBridge.ts)) automatically converts images to text when routing to non-vision models, respecting `maxImages` limits and DB configuration settings.
- All guardrails can be **disabled per request** using the `x-omniroute-disabled-guardrails` header, and the pipeline executes in [`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts) before and after upstream provider calls.

## Frequently Asked Questions

### How do I completely disable the PII-masker guardrail in OmniRoute?

Set the environment variable `PII_REDACTION_ENABLED=false` before starting the server. Alternatively, configure `INPUT_SANITIZER_MODE` to a value other than `redact` (e.g., `validate` or `off`) depending on your sanitization requirements. Since the guardrail checks these flags in its constructor and `preCall` method, changes require a server restart to take effect.

### What is the maximum payload size scanned for prompt injection attacks?

OmniRoute limits prompt injection scanning to the first **16 KB** (`MAX_INJECTION_SCAN_BYTES`) of extracted message content. This prevents performance degradation on large payloads while catching attacks that typically appear in the initial system prompt or user message. If your use case requires scanning larger contexts, you must modify the constant in [`src/lib/guardrails/promptInjection.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/promptInjection.ts) and rebuild the application.

### Can I use the vision-bridge with custom vision models instead of the default?

Yes. The `callVisionModel()` function in [`src/lib/guardrails/visionBridge.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/guardrails/visionBridge.ts) resolves the vision model endpoint from database settings ([`src/lib/db/settings.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/lib/db/settings.ts)) and constants in [`src/shared/constants/visionBridgeDefaults.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/constants/visionBridgeDefaults.ts). Configure your custom vision model credentials and endpoint in the settings table, and the guardrail will route image processing through your specified model before replacing image blocks with descriptions in the main request payload.

### How are guardrail results reflected in API responses?

When a guardrail modifies a payload or response, the `modifiedPayload` or `modifiedResponse` fields are passed downstream. For observability, the chat handler includes guardrail metadata in the response headers or body (depending on your configuration), indicating which guardrails executed, whether they modified content, and detection counts (e.g., PII entities redacted). Blocked requests return a 400-level error with a message generated by the blocking guardrail, such as "Request rejected: suspicious content detected" from the prompt-injection guard.