From 8b6d0d153ff31e29208f5e1b58ab31d57fabd055 Mon Sep 17 00:00:00 2001 From: Dexploarer <211557447+Dexploarer@users.noreply.github.com> Date: Sat, 25 Apr 2026 01:03:37 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20Fi?= =?UTF-8?q?x=20length=20timing=20oracle=20in=20token=20matching?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth-routes.ts | 10 +++++++++- src/api/server.ts | 7 ++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/api/auth-routes.ts b/src/api/auth-routes.ts index 9f7d1e8e02..07e4f9207d 100644 --- a/src/api/auth-routes.ts +++ b/src/api/auth-routes.ts @@ -78,7 +78,15 @@ export async function handleAuthRoutes( const expected = normalizePairingCode(current); const a = Buffer.from(expected, "utf8"); const b = Buffer.from(provided, "utf8"); - if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) { + let match = true; + if (a.length !== b.length) { + const padded = Buffer.alloc(a.length); + b.copy(padded, 0, 0, Math.min(b.length, a.length)); + match = crypto.timingSafeEqual(a, padded) && false; + } else { + match = crypto.timingSafeEqual(a, b); + } + if (!match) { error(res, "Invalid pairing code", 403); return true; } diff --git a/src/api/server.ts b/src/api/server.ts index c277040870..c84edacc1b 100644 --- a/src/api/server.ts +++ b/src/api/server.ts @@ -4463,7 +4463,12 @@ export function resolveHyperscapeAuthorizationHeader( function tokenMatches(expected: string, provided: string): boolean { const a = Buffer.from(expected, "utf8"); const b = Buffer.from(provided, "utf8"); - if (a.length !== b.length) return false; + if (a.length !== b.length) { + // Pad to equal length to avoid length oracle + const padded = Buffer.alloc(a.length); + b.copy(padded, 0, 0, Math.min(b.length, a.length)); + return crypto.timingSafeEqual(a, padded) && false; + } return crypto.timingSafeEqual(a, b); }