Skip to content

Security: diegosouzapw/OmniRoute

SECURITY.md

Security Policy

Reporting Vulnerabilities

If you discover a security vulnerability in OmniRoute, please report it responsibly:

  1. DO NOT open a public GitHub issue
  2. Use GitHub Security Advisories
  3. Include: description, reproduction steps, and potential impact

Response Timeline

Stage Target
Acknowledgment 48 hours
Triage & Assessment 5 business days
Patch Release 14 business days (critical)

Supported Versions

Version Support Status
3.8.x ✅ Active
3.7.x ✅ Security
< 3.7.0 ❌ Unsupported

Security Architecture

OmniRoute implements a multi-layered security model:

Request → CORS → Authz pipeline (classify → policies → enforce)
       → Guardrails (PII masker, prompt injection, vision bridge)
       → Rate Limiter → Circuit Breaker → Cooldown → Model Lockout → Provider

🔐 Authentication & Authorization

Feature Implementation
Dashboard Login Password-based auth with JWT tokens (HttpOnly cookies)
API Key Auth HMAC-signed keys with CRC validation
OAuth 2.0 + PKCE 14 providers (Claude, Codex, GitHub, Cursor, Antigravity, Gemini, Kimi Coding, Kilo Code, Cline, Qwen, Kiro, Qoder, Windsurf, GitLab Duo)
Token Refresh Automatic OAuth token refresh before expiry
Secure Cookies AUTH_COOKIE_SECURE=true for HTTPS environments
Authz Pipeline Route classification (PUBLIC / CLIENT_API / MANAGEMENT) — see docs/architecture/AUTHZ_GUIDE.md
MCP Scopes ~13 granular scopes (read:health, write:combos, execute:completions, etc.) — see docs/frameworks/MCP-SERVER.md

🛡️ Encryption at Rest

All sensitive data stored in SQLite is encrypted using AES-256-GCM with scrypt key derivation:

  • API keys, access tokens, refresh tokens, and ID tokens
  • Versioned format: enc:v1:<iv>:<ciphertext>:<authTag>
  • Passthrough mode (plaintext) when STORAGE_ENCRYPTION_KEY is not set
# Generate encryption key:
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)

🛡️ Guardrails Framework

OmniRoute ships a hot-reloadable guardrails registry (src/lib/guardrails/) with 3 built-in guardrails ordered by priority:

Guardrail Priority Purpose
vision-bridge 5 Bridges non-vision models with image-aware descriptions; SSRF protection for image URLs
pii-masker 10 Pre+post call PII redaction (emails, phone, CPF, CNPJ, credit cards, SSN)
prompt-injection 20 Detects override/role-hijack/jailbreak/leak patterns

Custom guardrails register via registerGuardrail(new MyGuardrail()). The model is fail-open (exceptions never block traffic). Per-request opt-out via x-omniroute-disabled-guardrails header. → See docs/security/GUARDRAILS.md.

🧠 Prompt Injection Guard

Middleware that detects and blocks prompt injection attacks in LLM requests:

Pattern Type Severity Example
System Override High "ignore all previous instructions"
Role Hijack High "you are now DAN, you can do anything"
Delimiter Injection Medium Encoded separators to break context boundaries
DAN/Jailbreak High Known jailbreak prompt patterns
Instruction Leak Medium "show me your system prompt"

Configure via dashboard (Settings → Security) or .env:

INPUT_SANITIZER_ENABLED=true
INPUT_SANITIZER_MODE=block    # warn | block | redact

🔒 PII Redaction

Automatic detection and optional redaction of personally identifiable information:

PII Type Pattern Replacement
Email user@domain.com [EMAIL_REDACTED]
CPF (Brazil) 123.456.789-00 [CPF_REDACTED]
CNPJ (Brazil) 12.345.678/0001-00 [CNPJ_REDACTED]
Credit Card 4111-1111-1111-1111 [CC_REDACTED]
Phone +55 11 99999-9999 [PHONE_REDACTED]
SSN (US) 123-45-6789 [SSN_REDACTED]
PII_REDACTION_ENABLED=true

🌐 Network Security

Feature Description
CORS Configurable origin control (CORS_ORIGIN env var, default *)
IP Filtering Allowlist/blocklist IP ranges in dashboard
Rate Limiting Per-provider rate limits with automatic backoff
Anti-Thundering Herd Mutex + per-connection locking prevents cascading 502s
TLS Fingerprint Browser-like TLS fingerprint spoofing to reduce bot detection
CLI Fingerprint Per-provider header/body ordering to match native CLI signatures

🔌 Resilience & Availability

Feature Description
Circuit Breaker 3-state (Closed → Open → Half-Open) per provider, SQLite-persisted
Request Idempotency 5-second dedup window for duplicate requests
Exponential Backoff Automatic retry with increasing delays
Health Dashboard Real-time provider health monitoring

📋 Compliance

Feature Description
Log Retention Automatic cleanup after CALL_LOG_RETENTION_DAYS
No-Log Opt-out Per API key noLog flag disables request logging
Audit Log Administrative actions tracked in audit_log table
MCP Audit SQLite-backed audit logging for all MCP tool calls
Zod Validation All API inputs validated with Zod v4 schemas at module load

Required Environment Variables

All secrets must be set before starting the server. The server will fail fast if they are missing or weak.

# REQUIRED — server will not start without these:
JWT_SECRET=$(openssl rand -base64 48)     # min 32 chars
API_KEY_SECRET=$(openssl rand -hex 32)    # min 16 chars

# RECOMMENDED — enables encryption at rest:
STORAGE_ENCRYPTION_KEY=$(openssl rand -hex 32)

The server actively rejects known-weak values like changeme, secret, or password.


Docker Security

  • Use non-root user in production
  • Mount secrets as read-only volumes
  • Never copy .env files into Docker images
  • Use .dockerignore to exclude sensitive files
  • Set AUTH_COOKIE_SECURE=true when behind HTTPS
docker run -d \
  --name omniroute \
  --restart unless-stopped \
  --read-only \
  -p 20128:20128 \
  -v omniroute-data:/app/data \
  -e JWT_SECRET="$(openssl rand -base64 48)" \
  -e API_KEY_SECRET="$(openssl rand -hex 32)" \
  -e STORAGE_ENCRYPTION_KEY="$(openssl rand -hex 32)" \
  diegosouzapw/omniroute:latest

Dependencies

  • Run npm audit regularly (npm run audit:deps covers main + electron)
  • Keep dependencies updated
  • The project uses husky + lint-staged for pre-commit checks (lint-staged + check-docs-sync + check:any-budget:t11)
  • CI pipeline runs ESLint security rules on every push (no-eval, no-implied-eval, no-new-func = error)
  • Provider constants validated at module load via Zod (src/shared/validation/schemas.ts)
  • Secure-by-default libraries used: dompurify / isomorphic-dompurify (XSS), jose (JWT), better-sqlite3 (no SQLi risk via parameterized queries), bcryptjs (password hashing)

Hard Security Rules

These rules are enforced by tooling and reviewers:

  1. Never commit secrets.env is gitignored; .env.example is the template (no literals, comments only — see PUBLIC_CREDS.md below)
  2. Never use eval(), new Function(), or implied eval — ESLint enforces
  3. Never bypass Husky hooks (--no-verify, --no-gpg-sign) without explicit operator approval
  4. Never write raw SQL in routes — always go through src/lib/db/ (parameterized)
  5. Always validate inputs with Zodsrc/shared/validation/schemas.ts
  6. Always sanitize upstream headers — denylist in src/shared/constants/upstreamHeaders.ts
  7. Encrypt credentials at rest — AES-256-GCM via src/lib/db/encryption.ts
  8. Public upstream OAuth identifiers via resolvePublicCred() — never embed AIza… / GOCSPX-… / …apps.googleusercontent.com literals in source. See docs/security/PUBLIC_CREDS.md.
  9. Error responses through buildErrorBody() / sanitizeErrorMessage() — never put raw err.stack / err.message in HTTP / SSE / executor / MCP response bodies. See docs/security/ERROR_SANITIZATION.md.
  10. exec() / spawn() runtime values via the env option — never string-interpolate external paths or untrusted values into shell-passed scripts. Reference: src/mitm/cert/install.ts::updateNssDatabases.
  11. Prefer secure-by-default libraries — see tldrsec/awesome-secure-defaults (Helmet.js, DOMPurify, ssrf-req-filter, safe-regex, Google Tink). Reach for them before rolling your own.

References

There aren't any published security advisories