# How OmniRoute Validates Incoming API Requests: A Complete Layered Security Guide

> Discover OmniRoute's multi-layer API request validation including CORS, Content-Type, Zod schemas, prompt-injection detection, and more. Secure your integrations today.

- Repository: [Diego Rodrigues de Sa e Souza/OmniRoute](https://github.com/diegosouzapw/OmniRoute)
- Tags: deep-dive
- Published: 2026-09-01

---

**OmniRoute performs multi-layer validation on incoming requests, combining CORS guards, Content-Type enforcement, byte-size admission controls, Zod schema validation, model availability checks, prompt-injection detection, and structural admission before any request reaches downstream providers.**

OmniRoute operates as a unified routing layer for multiple AI providers, making robust **request validation** essential for security, performance, and API consistency. The validation pipeline is deliberately layered—each stage filters out invalid or harmful traffic before expensive processing begins. This article examines the complete validation flow as implemented in `diegosouzapw/OmniRoute`, with specific file paths and code examples from the v3.8.51 release.

## Pre-Flight and Protocol Validation

### CORS and HTTP Method Enforcement

Every request first encounters the **CORS and HTTP method guard** in [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts). The `OPTIONS` function handles pre-flight requests and injects required `Access-Control-Allow-Origin` headers.

This layer prevents unwanted cross-origin calls and ensures clients use the correct HTTP verb before any payload processing occurs.

### Content-Type Strictness

OmniRoute rejects any request lacking the `application/json` Content-Type header. In [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts) (lines 94–100), mismatched headers trigger an immediate **415 Unsupported Media Type** response.

This mirrors OpenAI and Anthropic API behavior, ensuring bodies are parsed as JSON only.

```ts
// Valid request header
headers: {
  "Content-Type": "application/json",  // ✅ Required
}

```

```bash

# Rejected request example

curl -X POST http://localhost:20128/v1/chat/completions \
     -H "Content-Type: text/plain" \
     -d '{"model":"openai/gpt-4","messages":[]}'

# → 415 Unsupported Media Type

```

## Resource Protection and Admission Control

### Byte-Size Admission with Chat Admission Flow

Before parsing any body, OmniRoute enforces a **hard byte limit** through the `admitChatRequest` function in [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts) (lines 12–20). This reserves capacity and prevents oversized payloads from causing OOM crashes or resource exhaustion.

The admission logic lives in [`src/shared/middleware/chatBodyAdmission.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/middleware/chatBodyAdmission.ts), which handles capacity tracking and size enforcement.

### One-Time JSON Parsing

The request body is parsed exactly once via `await request.json()` at lines 44–46 of the completions route. Failed parsing immediately invalidates the request.

This guarantees a **single source of truth** for the body object and eliminates double-parsing overhead.

## Schema and Semantic Validation

### Top-Level Shape Guard with Zod

OmniRoute applies a **permissive Zod schema** that performs rapid structural validation:

- Parsed body must be an object
- `model` is optional and nullable (string)
- `messages` is optional (array)

Located at lines 77–82 of [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts), this schema uses `.passthrough()` mode—extra fields flow downstream untouched. The `safeParse` call at line 52 quickly weeds out non-object payloads (e.g., raw strings) without rejecting valid extensions.

```ts
// Zod shape guard (simplified)
const bodySchema = z.object({
  model: z.string().nullable().optional(),
  messages: z.array(z.any()).optional(),
}).passthrough();

```

### Model Availability and Retirement Guards

Two distinct checks verify model viability:

- **`assertCommonChatGptWebModelAvailable`** (lines 62–73): Validates against retired web-facing models
- **`assertRuntimeModelProviderAvailable`** (lines 91–98): Confirms the runtime provider still supports the requested model

If a model is deprecated, the system returns a provider-specific **400 or 404 error** with structured details like `{ type: "provider_error", code: "MODEL_RETIRING" }`.

```ts
// Example: Retired model rejection
await fetch("/v1/chat/completions", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ 
    model: "openai/old-model",  // ❌ Retired
    messages: [] 
  }),
});
// → 400 with provider error code

```

### Prompt-Injection Detection

The **Injection Guard middleware**—instantiated at line 42 as `injectionGuard` and invoked inside `handleChat`—scans request bodies for malicious prompt patterns before any provider forwarding.

This security layer in [`src/middleware/promptInjectionGuard.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/middleware/promptInjectionGuard.ts) blocks attempts to manipulate system behavior through carefully crafted inputs.

### Structural Admission with Full Chat Schema

After passing the shape guard, payloads undergo `admitChatStructure` validation (lines 76–86). This applies the **complete chat schema** defined in [`src/sse/handlers/chat.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/sse/handlers/chat.ts), verifying:

- Message object structure and valid roles
- Token limit compliance
- Tool call formatting
- Stream parameter validity

Only fully validated requests proceed to `handleChat` for provider dispatch.

## Cross-Endpoint Validation Standards

### Global Zod Schemas

Routes beyond chat completions import shared schemas from `src/shared/validation/schemas/*.ts`:

| Schema File | Purpose |
|-------------|---------|
| [`src/shared/validation/schemas/apiV1.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/apiV1.ts) | Pagination parameters, generic API IDs, limit specifications |
| [`src/shared/validation/schemas/provider.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/validation/schemas/provider.ts) | Provider IDs, model lists, provider-specific constraints |

These files provide a **single source of truth** for request contracts across the entire router surface.

### Route-Specific Guardrails

Individual endpoints add tailored validation layers:

- **[`src/app/api/v1/audio/speech/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/audio/speech/route.ts)**: Validates audio MIME types for synthesis requests
- **`src/app/api/v1/files/[id]/content/route.ts`**: Validates `Range` header formatting for partial content retrieval

Each route contains lightweight, semantic-appropriate guards that reduce bug surface area without duplicating global logic.

## Complete Validation Flow Overview

A typical chat request traverses this pipeline:

1. **CORS pre-flight** via `OPTIONS` handler
2. **Content-Type check** (reject non-JSON with 415)
3. **Byte-size admission** and capacity reservation
4. **Single JSON parse** with failure handling
5. **Top-level Zod shape guard** (permissive, passthrough)
6. **Model retirement guard** (web-model availability)
7. **Runtime provider availability check**
8. **Prompt-injection detection**
9. **Structural admission** (full chat schema validation)
10. **Dispatch to `handleChat`** for provider execution

Each layer fails fast with specific status codes and error messages, enabling precise client-side troubleshooting.

## Summary

- **Protocol validation** (CORS, Content-Type, HTTP methods) filters malformed traffic immediately in [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts)
- **Resource protection** via `admitChatRequest` enforces byte limits and capacity reservation before body parsing
- **Zod schema validation** operates in two phases: permissive shape guard first, full structural admission second
- **Security middleware** including `injectionGuard` and model availability checks prevents malicious or obsolete requests from reaching providers
- **Shared schema files** in `src/shared/validation/schemas/` maintain API consistency across all endpoints
- **Route-specific guards** add semantic validation tailored to individual endpoint requirements

## Frequently Asked Questions

### What happens if I send the wrong Content-Type header?

OmniRoute returns **415 Unsupported Media Type** immediately. The check at lines 94–100 of [`src/app/api/v1/chat/completions/route.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/app/api/v1/chat/completions/route.ts) enforces strict `application/json` requirements to match OpenAI/Anthropic API behavior and ensure safe body parsing.

### How does OmniRoute prevent oversized request bodies from crashing the server?

The **Chat Admission flow** in [`src/shared/middleware/chatBodyAdmission.ts`](https://github.com/diegosouzapw/OmniRoute/blob/main/src/shared/middleware/chatBodyAdmission.ts) enforces hard byte limits and reserves capacity before any JSON parsing occurs. This prevents memory exhaustion from malicious or accidental large payloads.

### Can additional fields be included in the request body beyond the documented parameters?

Yes. The top-level Zod schema uses `.passthrough()` mode, allowing extra fields to flow downstream unchanged. Only the core structure (object type, optional `model` string, optional `messages` array) is validated at the initial layer.

### What error code is returned for retired or unsupported models?

The system returns **400 Bad Request** with a structured error object containing `type: "provider_error"` and `code: "MODEL_RETIRING"` or similar provider-specific codes. This occurs after the `assertCommonChatGptWebModelAvailable` or `assertRuntimeModelProviderAvailable` checks fail.