Problem
The desktop app currently receives the master ElevenLabs API key directly via GET /v1/config/api-keys. Every authenticated user gets the same key (sk_da7e7c3ea...f6f2, 51 chars) with no per-user scoping or rate limiting.
This means:
- Any user can extract the key and use it outside the app
- No per-user usage tracking or cost control
- A single abusive user can exhaust the entire ElevenLabs quota
- Key rotation requires a new app release or backend deploy + all clients refetching
Solution
Proxy all ElevenLabs API calls through the Omi backend instead of giving clients the raw key.
Backend changes (Rust desktop-backend)
- Add a new endpoint:
POST /v1/tts/synthesize (or similar) that accepts text + voice config
- Backend calls ElevenLabs API server-side using the master key
- Enforce per-user rate limits (e.g., N requests/minute, M characters/day)
- Stream audio response back to the client
- Log usage per user for cost attribution
Desktop app changes (Swift)
- Replace direct ElevenLabs API calls with calls to the new backend endpoint
- Remove
elevenlabs_api_key from APIKeyService / stop requesting it from /v1/config/api-keys
- Remove
ELEVENLABS_API_KEY from environment variable injection
Rate limit suggestions
- Per-user: ~50 requests/minute, ~10,000 characters/day
- Global: circuit breaker if monthly spend exceeds budget threshold
- Return
429 Too Many Requests with retry-after header when limits hit
Current flow (insecure)
Swift app → GET /v1/config/api-keys → receives raw ElevenLabs key
Swift app → ElevenLabs API (direct, using raw key)
Target flow (secure)
Swift app → POST /v1/tts/synthesize → Rust backend → ElevenLabs API
(rate limit + usage tracking)
Files involved
desktop/Backend-Rust/src/routes/config.rs — stop serving elevenlabs_api_key
desktop/Backend-Rust/src/routes/ — new TTS proxy route
desktop/Desktop/Sources/APIKeyService.swift — remove ElevenLabs key handling
desktop/Desktop/Sources/ — update ElevenLabs callers to use backend proxy
Related
- Security audit finding: master API keys distributed to all users via
/v1/config/api-keys (CRITICAL)
- Anthropic key has the same problem (separate issue for that)
Problem
The desktop app currently receives the master ElevenLabs API key directly via
GET /v1/config/api-keys. Every authenticated user gets the same key (sk_da7e7c3ea...f6f2, 51 chars) with no per-user scoping or rate limiting.This means:
Solution
Proxy all ElevenLabs API calls through the Omi backend instead of giving clients the raw key.
Backend changes (Rust desktop-backend)
POST /v1/tts/synthesize(or similar) that accepts text + voice configDesktop app changes (Swift)
elevenlabs_api_keyfromAPIKeyService/ stop requesting it from/v1/config/api-keysELEVENLABS_API_KEYfrom environment variable injectionRate limit suggestions
429 Too Many Requestswith retry-after header when limits hitCurrent flow (insecure)
Target flow (secure)
Files involved
desktop/Backend-Rust/src/routes/config.rs— stop servingelevenlabs_api_keydesktop/Backend-Rust/src/routes/— new TTS proxy routedesktop/Desktop/Sources/APIKeyService.swift— remove ElevenLabs key handlingdesktop/Desktop/Sources/— update ElevenLabs callers to use backend proxyRelated
/v1/config/api-keys(CRITICAL)