fix: replace SHA-256 with HKDF + per-row salt for user API key encryption
From the PR description
Summary
- Replaces the single-SHA-256
encryptionKey()with HKDF (RFC 5869) and a per-row random 16-byte salt, eliminating the one-hash-breaks-all vulnerability - Backward-compatible: rows with
salt IS NULLstill decrypt via the legacy SHA-256 path; new and updated rows automatically use HKDF - Adds a
salt textcolumn to theuser_api_keystable (nullable for compatibility with existing rows)
Closes #67
Changes
backend/src/lib/userApiKeys.ts-encryptKey/decryptKeyexported helpers;deriveKeyuseshkdfSyncwith per-row salt;legacyKeycovers null-salt rowsbackend/schema.sql-salt textcolumn added touser_api_keys; runALTER TABLE public.user_api_keys ADD COLUMN IF NOT EXISTS salt text;on existing databasesbackend/vitest.config.ts+backend/package.json- vitest test runner addedbackend/src/lib/__tests__/userApiKeys.test.ts- 5 unit tests covering HKDF round-trip, unique salts/IVs, tamper detection, and legacy SHA-256 compat
Test plan
- Unit tests: encrypt→decrypt round-trip, unique salt per call, tamper detection, legacy null-salt backward compat
- Build and typecheck pass
Our analysis
Replace SHA-256 key derivation with HKDF and per-row salt — 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-76.md from
inside the repo you want the changes in.