Description
All users share a single SETTINGS_ENCRYPTION_KEY environment variable to encrypt/decrypt their API keys and secrets. The GET /api/settings/crypto-key endpoint returns this same key to every authenticated user.
If any single user's key is compromised, or the environment variable leaks, all users' encrypted secrets can be decrypted.
Location
apps/web/src/lib/server-crypto.ts — single shared key for all encrypt/decrypt operations
apps/web/src/app/api/settings/crypto-key/route.ts — returns the same key to every user
Impact
- Severity: HIGH (design-level)
- Single point of failure: one key compromise affects all users
- Violates multi-tenant isolation guarantees
- Circumvents per-user RLS protections in the database
Suggested Fix
Derive per-user encryption keys from the master key + user ID:
import { createHmac } from 'crypto';
function deriveUserKey(masterKey: Buffer, userId: string): Buffer {
return createHmac('sha256', masterKey)
.update(userId)
.digest();
}
This ensures each user's data is encrypted with a unique key while only requiring one master secret in the environment.
Description
All users share a single
SETTINGS_ENCRYPTION_KEYenvironment variable to encrypt/decrypt their API keys and secrets. TheGET /api/settings/crypto-keyendpoint returns this same key to every authenticated user.If any single user's key is compromised, or the environment variable leaks, all users' encrypted secrets can be decrypted.
Location
apps/web/src/lib/server-crypto.ts— single shared key for all encrypt/decrypt operationsapps/web/src/app/api/settings/crypto-key/route.ts— returns the same key to every userImpact
Suggested Fix
Derive per-user encryption keys from the master key + user ID:
This ensures each user's data is encrypted with a unique key while only requiring one master secret in the environment.