From 7073a9e1787550e8fc831dfac3071c6e1da91875 Mon Sep 17 00:00:00 2001 From: adityabhatkar23 Date: Sat, 13 Jun 2026 22:09:08 +0530 Subject: [PATCH] fix: properly validate JWT signatures in verifyJwt Ensure tampered signatures are rejected and return null as expected. Add explicit length checks and base64url error handling. Fixes: #761 --- backend/src/middleware/auth.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/backend/src/middleware/auth.ts b/backend/src/middleware/auth.ts index b9694d1..082d447 100644 --- a/backend/src/middleware/auth.ts +++ b/backend/src/middleware/auth.ts @@ -98,13 +98,31 @@ export function verifyJwt(token: string): { publicKey: string } | null { try { const [header, body, sig] = token.split('.'); if (!header || !body || !sig) return null; + + // Verify signature const expected = crypto .createHmac('sha256', JWT_SECRET) .update(`${header}.${body}`) .digest(); - if (!crypto.timingSafeEqual(Buffer.from(sig, 'base64url'), expected)) return null; + + let providedSig: Buffer; + try { + providedSig = Buffer.from(sig, 'base64url'); + } catch { + return null; + } + + // Use timingSafeEqual to prevent timing attacks + if (providedSig.length !== expected.length || !crypto.timingSafeEqual(providedSig, expected)) { + return null; + } + + // Verify expiration const payload = JSON.parse(Buffer.from(body, 'base64url').toString()); - if (payload.exp < Math.floor(Date.now() / 1000)) return null; + if (!payload.exp || payload.exp < Math.floor(Date.now() / 1000)) { + return null; + } + return { publicKey: payload.sub }; } catch { return null;