Opus finding
Timing-safe auth compare leaks via length check and fails when client omits header
lowsecuritymedium
- apps/web/app/api/cron/review-retry/route.ts:22-31
The length-based early return leaks the expected token length via a timing side-channel; the conventional fix is to hash both sides (or pad/compare a fixed-length digest) before timingSafeEqual. The risk in practice is low because (a) the secret length is itself usually not sensitive and (b) Vercel cron is the only legitimate caller, but the code intentionally uses timingSafeEqual to be defensive, so the half-measure undermines the stated intent. Note: this is the standard idiom Vercel docs themselves use, so severity is low.
Recommendation
Hash both sides with SHA-256 first so the buffers compared are always 32 bytes: `const ah = createHash('sha256').update(provided).digest(); const bh = createHash('sha256').update(expected).digest(); if (!timingSafeEqual(ah, bh)) ...`.