Security Considerations for OmniRoute's Streaming Engine: Protecting SSE Streams from Data Leaks and Abuse
OmniRoute's streaming engine implements rigorous sanitization, resource limits, and injection guards to prevent information leakage, denial-of-service, and unauthorized function execution in Server-Sent Event streams.
The streaming engine in diegosouzapw/OmniRoute processes raw provider SSE (Server-Sent Events) streams within the open-sse/ workspace, transforming them into safe client responses. Understanding the security considerations for OmniRoute's streaming engine is critical for deployments handling sensitive LLM outputs and upstream provider credentials. The codebase implements defense-in-depth through automated error sanitization, idle timeout protection, and strict tool-call validation.
Error Sanitization and Safe Response Generation
OmniRoute ensures that raw stack traces, absolute file paths, and internal secrets never reach the client. The open-sse/utils/error.ts module provides centralized utilities for sanitizing all error output.
Automated Stack Trace and Path Removal
The sanitizeErrorMessage() function strips multi-line stack traces and replaces POSIX or Windows paths with the literal <path> placeholder. This prevents accidental exposure of deployment directory structures or internal file systems that could aid attackers in mapping the server environment.
Centralized Error Construction with buildErrorBody
All error responses route through buildErrorBody(), which internally calls sanitizeErrorMessage(). Whether handling HTTP route failures or SSE stream errors via emitClaudeEmptyStreamErrorAndAbort, developers never manually clean messages. The utility guarantees consistent redaction across all exit points.
import { buildErrorBody } from '@omniroute/open-sse/utils/error.ts';
export async function POST(req: Request) {
try {
// … normal handling …
} catch (err) {
// Sanitizes stack traces and path leaks automatically.
return new Response(JSON.stringify(buildErrorBody(500, String(err))), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}
Stream Integrity and Resource Protection
The createSSEStream() function in open-sse/utils/stream.ts manages the transform stream with a single exit point (doneSent) and safeguards against stalled connections and resource exhaustion.
Idle Timeout Watchdog (STREAM_IDLE_TIMEOUT_MS)
A periodic check runs every 10 seconds to compare the current time against the last received chunk. If the gap exceeds the configurable STREAM_IDLE_TIMEOUT_MS defined in open-sse/config/constants.ts, the stream aborts with a sanitized StreamIdleTimeoutError. This prevents denial-of-service attacks via hung upstream connections that would otherwise hold server resources indefinitely.
Back-Pressure and Termination Safeguards
The engine caps accumulated payloads at STREAM_SUMMARY_TEXT_LIMIT and injects synthetic [DONE] terminators only when appropriate via shouldEmitDoneTerminator. It also detects duplicate Responses-API sequence numbers, dropping replayed events to prevent client-side duplication attacks and ensure exactly-once delivery semantics.
import { createSSEStream } from '@omniroute/open-sse/utils/stream.ts';
const sse = createSSEStream({
mode: 'translate',
sourceFormat: 'openai',
targetFormat: 'claude',
provider: 'anthropic',
model: 'claude-3-5-sonnet-20240620',
onFailure: (payload) => {
// Custom hook still routes through buildErrorBody for sanitization.
console.warn('Stream failed', payload);
},
});
Tool Call Injection Prevention
Textual tool-call hints from models could trigger arbitrary function execution if not properly validated against the request's original intent.
Validating Textual Tool Calls
The applyTextualToolCallStreamingGuard in open-sse/utils/stream.ts parses candidate [Tool call: …] blocks. It uses extractAllowedToolNames to build an allowlist from the request's tools array, checking each candidate with containsMalformedTextualToolCall().
Strict Allowlist Enforcement
Any tool call not explicitly defined in the original request is discarded or neutralized. This prevents attackers from forcing arbitrary function execution via crafted model output that references disallowed functions.
import { extractAllowedToolNames, containsMalformedTextualToolCall } from '@omniroute/open-sse/utils/stream.ts';
const allowed = extractAllowedToolNames(requestBody);
if (containsMalformedTextualToolCall(candidateString, allowed)) {
// Reject or drop the chunk – no rogue function call will be emitted.
}
Credential and Header Safety
Upstream authentication must never echo back to clients or appear in external logs.
Public Credential Isolation
The open-sse/utils/publicCreds.ts helper centralizes public credential handling with a strict "public-only" whitelist. Private keys remain isolated in the executor layer (executors/*.ts), where headers are injected upstream but never mirrored in downstream responses.
Log Redaction Policies
Before sanitization for clients, errors are logged via pino or console. The src/shared/utils/logRedaction.ts module defines redaction patterns for structured logs, ensuring secrets never reach external log sinks that might be shipped off-site.
Guardrail Defaults and Policy Enforcement
Security controls default to disabled to prevent accidental payload modification or information leakage through over-sanitization.
Opt-In Security Controls
The guardrail system respects the x-omniroute-disabled-guardrails header, but defaults to false (off) as documented in the guardrail policy. This opt-in approach prevents accidental PII masking or prompt injection blocks unless explicitly enabled, avoiding unintended data leakage through aggressive filtering.
Summary
- Error sanitization via
buildErrorBody()andsanitizeErrorMessage()inopen-sse/utils/error.tsprevents stack trace and path leakage to clients. - Idle timeout protection using
STREAM_IDLE_TIMEOUT_MSinopen-sse/utils/stream.tsmitigates resource exhaustion attacks from stalled providers. - Tool-call validation through
extractAllowedToolNamesandcontainsMalformedTextualToolCallblocks injection attacks against unauthorized functions. - Credential isolation in
open-sse/utils/publicCreds.tsensures private keys never reach clients or logs, with log redaction rules insrc/shared/utils/logRedaction.ts. - Back-pressure controls including
STREAM_SUMMARY_TEXT_LIMITand duplicate detection prevent memory exhaustion and replay attacks. - Opt-in guardrails default to disabled to prevent accidental data modification or leakage through over-sanitization.
Frequently Asked Questions
How does OmniRoute prevent stack traces from leaking to clients?
OmniRoute's streaming engine routes all errors through buildErrorBody() in open-sse/utils/error.ts, which calls sanitizeErrorMessage() to strip multi-line stacks and replace file paths with <path> placeholders. This ensures that raw exception details never reach the SSE stream or HTTP response, regardless of where the error originates.
What protects against stalled provider connections in the streaming engine?
The createSSEStream() function implements an idle-timeout watchdog that checks every 10 seconds against STREAM_IDLE_TIMEOUT_MS defined in open-sse/config/constants.ts. If the upstream provider stalls beyond this threshold, the stream aborts with a sanitized StreamIdleTimeoutError, preventing resource exhaustion and ensuring clients receive a clean termination rather than an indefinite hang.
How does OmniRoute validate tool calls to prevent arbitrary function execution?
The engine parses textual [Tool call: …] blocks using applyTextualToolCallStreamingGuard in open-sse/utils/stream.ts. It validates candidates against an allowlist built via extractAllowedToolNames from the original request's tools array, discarding any tool calls not explicitly permitted. This prevents attackers from injecting calls to disallowed functions through crafted model outputs.
Where are upstream credentials handled to prevent exposure in responses and logs?
Upstream credentials are injected via headers in the executor layer and isolated by open-sse/utils/publicCreds.ts, which enforces a public-only whitelist. Private keys never echo back to clients. Additionally, src/shared/utils/logRedaction.ts defines redaction patterns for structured logs, ensuring sensitive values never appear in log streams shipped to external sinks.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →