Security & data handling
Tenancy, secrets, retention, and how request payloads are treated.
Tenancy isolation
Every tenant-owned table enforces Postgres row-level security (default-deny, keyed on the workspace), and every management route enforces authorization at three layers: route middleware (RBAC), the service function (re-derived RBAC), and RLS. Owner/admin actions require 2FA. Once an account has an authenticator (TOTP) enrolled, signing in to the dashboard is two steps: the password, then the 6-digit code from the authenticator app (optionally trusting the device for 30 days).
Secrets
- API keys — only a SHA-256 hash and a display prefix are stored; the raw
ur_sk_*secret is returned exactly once on create/roll and never logged. - BYOK & custom-provider secrets — envelope-encrypted (a per-workspace data key wrapped by a versioned master key), decrypted only in memory at call time, zeroized after use, and never returned by the API (last-4 display only).
- Secrets never appear in logs or audit diffs.
Request/response payloads
The gateway never logs request or response bodies — logs carry ids, lengths, and hashes only. Whether bodies are stored is controlled per workspace by the retention mode:
none— nothing stored.metadata(default) — request metadata only.full— bodies stored (gzip, 32 KB-capped) so you can reveal them in the logs explorer. Revealing a payload is retention-gated and audited.
A configurable TTL (1–90 days, default 30) plus a retention sweeper hard-delete stored payloads past their window, with a per-workspace audit summary.
Audit trail
Mutations write to a hash-chained, append-only audit log; a nightly worker re-verifies the chain. The dashboard audit viewer shows a per-row tamper-evidence badge.
Egress (SSRF)
Custom-provider egress is guarded: HTTPS-only (loopback HTTP only behind an explicit dev flag), DNS-resolved and rejected for private/link-local/metadata ranges, and re-validated on every redirect (max 2).
Webhooks
Webhook secrets are envelope-encrypted; deliveries are HMAC-signed
(X-UR-Signature: sha256=… over <timestamp>.<body>) and the target URL is
SSRF-validated on create and edit.
Region & hosting
Single-region v1; the region is disclosed read-only in settings. The hosted gateway
(https://api.ultrarouter.io) is invite-only for now: invited accounts sign in at
https://app.ultrarouter.io and bring their own provider keys, which are
envelope-encrypted at rest. There is no hosted MCP endpoint. You can also self-host or
run the stack locally.