harden(browse): constant-time bearer-token comparison in validateAuth

The loopback auth check compared the Authorization header with `===`, whose
byte-by-byte early exit leaks the token prefix through response timing. Use
crypto.timingSafeEqual with a length gate (the length is not secret). Behavior
is unchanged for valid/invalid tokens; auth tests unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-16 10:14:33 -07:00
co-authored by Claude Fable 5
parent 93fefbdccd
commit d2d0ffdf59
+7 -1
View File
@@ -1720,7 +1720,13 @@ export function buildFetchHandler(cfg: ServerConfig): ServerHandle {
// validateAuth was deleted in v1.35.0.0.
function validateAuth(req: Request): boolean {
const header = req.headers.get('authorization');
return header === `Bearer ${authToken}`;
if (header === null) return false;
// Constant-time compare so a byte-by-byte early-exit can't leak the token
// prefix via response timing. timingSafeEqual requires equal-length inputs,
// so the length check gates it (the length itself is not secret).
const got = Buffer.from(header);
const want = Buffer.from(`Bearer ${authToken}`);
return got.length === want.length && crypto.timingSafeEqual(got, want);
}
// Factory-scoped shutdown. Closes the cfg-provided browserManager so