Security

How we protect your keys.

Last updated: April 18, 2026

You're trusting Obol with provider API keys that can make inference calls and read billing data. We take that seriously. This page explains exactly what we do with your keys and how the system is built to minimize risk.

Encryption at rest

  • Every API key is encrypted with AES-256-GCM before it touches the database. Each key gets its own random initialization vector (IV) — even if two users paste the same key, the ciphertexts are different.
  • The master encryption key lives in Cloudflare Pages secrets, not in code or in the database. It is never committed to version control.
  • Proxy virtual keys (obol_sk_live_...) are hashed with SHA-256 at rest. The raw token is shown once on creation and never stored or recoverable.

Password security

  • Passwords are hashed with PBKDF2-SHA256 at 100,000 iterations with a per-user random salt. We never store or log plaintext passwords.
  • Password reset tokens are SHA-256 hashed, single-use, and expire after 60 minutes. Redeeming a reset invalidates all other active sessions.

Admin vs inference key separation

For OpenAI and Anthropic, Obol uses two separate keys per connection:

  • Admin key — read-only access to billing and usage APIs. Used by the hourly sync. Cannot make inference calls.
  • Inference key — used only by the LLM proxy to forward your requests. Can make API calls but cannot read billing.

This means a compromised sync path cannot generate AI completions, and a compromised proxy path cannot read your billing history. For other providers (OpenRouter, Groq, Mistral, etc.) the same key handles both — those providers don't offer separate admin keys.

What we never log

  • Plaintext API keys — encrypted before storage, never in logs.
  • Request/response content — the proxy forwards bytes without reading prompt or completion text.
  • Plaintext passwords — hashed immediately on receipt.
  • Plaintext virtual keys — hashed with SHA-256, shown once.

Structured logs contain: user ID, provider name, model name, token counts, cost, latency, HTTP status. Never secrets. Never content.

We do capture each proxy request's User-Agent header and source IP (via cf-connecting-ip) on the audit row, so the /monitor dashboard can show SDK and geographic breakdowns. Both fields stay server-side: User-Agent is classified into a coarse SDK identifier (openai-python, curl, etc.) before display, and IPs are bucketed to /24 (IPv4) or /64 (IPv6) — raw addresses are never rendered.

Proxy security model

  • The proxy is a byte-for-byte passthrough. Request and response bodies are tee'd through a TransformStream for token counting — never buffered, never stored, never logged.
  • Virtual keys support IP allowlists, provider restrictions, model glob filters, and monthly budget caps — so you can scope keys to exactly what each app or team member needs.
  • Bearer token authentication. No cookies are involved in proxy auth, eliminating CSRF as an attack vector on proxy endpoints.

Infrastructure

  • Cloudflare Workers — code runs at the edge in an isolated V8 sandbox per request. No shared process memory between users.
  • Cloudflare D1 — SQLite at the edge. Database is encrypted at rest by Cloudflare. Located in APAC region.
  • Cloudflare KV — sessions stored with 30-day TTL and auto-expiration. Rate-limit counters expire automatically.
  • HTTPS only — all traffic is TLS-encrypted in transit. No plain HTTP endpoints.

Keplor (log aggregator)

Per-request proxy analytics are powered by Keplor, an open-source observational proxy written in Rust.

  • Metadata only — Keplor receives model name, provider, token counts, cost, latency, and HTTP status. It never receives prompt text, completion text, or API keys.
  • API key auth — Keplor validates every ingestion request with constant-time HMAC comparison. No open endpoints.
  • Compressed storage — zstd compression with trained dictionaries achieves 30-80x ratios. 90-day retention with automatic garbage collection.
  • Open source — the full Keplor codebase is public. You can audit exactly what data it stores and how it processes events.

CSRF protection

All mutation endpoints check the Origin header against the app's own origin. Cross-origin POST requests are rejected with 403. Webhook endpoints (Razorpay) are exempted but verified with HMAC-SHA256 signature checks. Proxy endpoints use bearer tokens, not cookies, so CSRF does not apply.

Data retention and deletion

  • Free plan: 7-day usage history. Pro plan: 90-day history.
  • Data beyond the retention window is automatically purged by the daily cleanup job.
  • Account deletion cascades to all connections, usage records, alerts, proxy keys, and billing data. The delete is immediate and irreversible.

No tracking

Obol has no analytics cookies, no third-party trackers, no pixel tags, no fingerprinting. No data is sold or shared with advertisers. The only third-party service that receives your data is Razorpay for payment processing.

Reporting a vulnerability

If you find a security issue, email kumarashutosh34169@gmail.com with details. We'll acknowledge within 48 hours and work on a fix before any public disclosure.