fix: require dedicated secrets for download signing and API key encryption
From the PR description
Summary
- Remove
SUPABASE_SECRET_KEYfallback fromdownloadTokens.getSecret()-DOWNLOAD_SIGNING_SECRETis now required - Remove three-way fallback from
userApiKeys.encryptionKey()-USER_API_KEYS_ENCRYPTION_SECRETis now required - Add
assertSecretIsolation()called at server startup to enforce presence, uniqueness, and cross-secret isolation of each secret - Updates JSDoc comment in
downloadTokens.tsto reflect the TTL-based expiration added in PR #77
Closes #66 Closes #82 Closes #83 Closes #88
Changes
backend/src/lib/downloadTokens.ts-getSecret()reads onlyDOWNLOAD_SIGNING_SECRET; JSDoc updated to reference configurable TTLbackend/src/lib/userApiKeys.ts-encryptionKey()reads onlyUSER_API_KEYS_ENCRYPTION_SECRETbackend/src/lib/startup.ts- newassertSecretIsolation()validates at boot: missing vars throw, secrets matchingSUPABASE_SECRET_KEYthrow, andDOWNLOAD_SIGNING_SECRET === USER_API_KEYS_ENCRYPTION_SECRETthrowsbackend/src/index.ts- callassertSecretIsolation()before the server startsbackend/vitest.config.ts- vitest config excludingdist/backend/src/lib/__tests__/secretIsolation.test.ts- 11 vitest unit tests covering all paths
Test plan
-
npm testpasses (11/11) inbackend/ -
npm run buildpasses with no TypeScript errors -
.envmust be updated before restarting backend (see migration note below)
⚠️ Migration note
Before restarting the backend after this change, ensure your environment has:
DOWNLOAD_SIGNING_SECRET=<dedicated random value>
USER_API_KEYS_ENCRYPTION_SECRET=<dedicated random value>
Generate fresh values with openssl rand -hex 32.
If you previously had API_KEYS_ENCRYPTION_SECRET set (an undocumented legacy fallback that was removed in this PR): set USER_API_KEYS_ENCRYPTION_SECRET to that same value. Do not generate a new value - doing so will change the AES key and make all stored user API keys in the database unreadable.
Our analysis
Make per-purpose secrets mandatory and enforce isolation at boot — read the full analysis →
Think the analysis missed something the PR description covers?
Capture this PR into my fork
Download a Markdown prompt that tells Claude how to port every
commit in this PR into your working tree. Run it via
claude -p < capture-pull-74.md from
inside the repo you want the changes in.