From 93707016a19c6add2ba1b89a264b1d1bd834ec05 Mon Sep 17 00:00:00 2001 From: Blake Bertuccelli-Booth <46652+bbertucc@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:29:52 -0400 Subject: [PATCH 1/2] fix: CodeQL's three open src alerts (bearer-header regex, req.files type) The bearer regexes in middleware.ts and quality.ts become /^Bearer\s+(\S.*)$/i, which is linear. An all-whitespace token was already refused and still is. sessions.ts reads req.files with Array.isArray instead of a cast. Co-Authored-By: Claude Opus 5.5 --- src/auth/middleware.ts | 2 +- src/routes/quality.ts | 2 +- src/routes/sessions.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/auth/middleware.ts b/src/auth/middleware.ts index 7254172..f4a88d4 100644 --- a/src/auth/middleware.ts +++ b/src/auth/middleware.ts @@ -85,7 +85,7 @@ export function makeAuthMiddleware(store: Store, cfg: IrisConfig) { // other: a caller who presents the gate token is not thereby anybody. if (gate !== undefined) { const header = req.header("authorization") ?? ""; - const match = header.match(/^Bearer\s+(.+)$/i); + const match = header.match(/^Bearer\s+(\S.*)$/i); // Compared after trimming, because `apiToken` trims what it read from config: a // configured `" s3cret "` must not be a gate that only an untrimmed copy opens. if (!match || match[1].trim() !== gate) { diff --git a/src/routes/quality.ts b/src/routes/quality.ts index d19642d..b95c805 100644 --- a/src/routes/quality.ts +++ b/src/routes/quality.ts @@ -29,7 +29,7 @@ function tokenMatches(presented: string, configured: string): boolean { // The bearer token on the request, if it presented one in the form the rest of the // API uses. function bearer(header: string | undefined): string | null { - const m = /^Bearer\s+(.+)$/i.exec(header ?? ""); + const m = /^Bearer\s+(\S.*)$/i.exec(header ?? ""); return m ? m[1].trim() : null; } diff --git a/src/routes/sessions.ts b/src/routes/sessions.ts index 515db69..330f671 100644 --- a/src/routes/sessions.ts +++ b/src/routes/sessions.ts @@ -281,7 +281,7 @@ export function sessionsRouter(cfg: IrisConfig, store: Store): Router { // first (free), then how many bytes of upload are already arriving, then the caller's // upload budget for the minute — and only then is a byte of this body read. r.post("/", requestSizeGate(), inFlightUploads, uploadBudget, uploadImages, async (req: AuthedRequest, res) => { - const files = (req.files as Express.Multer.File[] | undefined) ?? []; + const files = Array.isArray(req.files) ? req.files : []; if (files.length === 0) { sendError(res, 400, "invalid_request", "At least one file part named 'images' is required (image or PDF)"); return; From b9d497b9598129c9be4755dcd590be1dc2dd15f8 Mon Sep 17 00:00:00 2001 From: Blake Bertuccelli-Booth <46652+bbertucc@users.noreply.github.com> Date: Thu, 1 Oct 2026 09:43:20 -0400 Subject: [PATCH 2/2] test(quality): a whitespace-padded bearer token opens the endpoint Co-Authored-By: Claude Opus 5.5 --- test/quality-route.test.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/quality-route.test.ts b/test/quality-route.test.ts index 712ad31..8bb71d3 100644 --- a/test/quality-route.test.ts +++ b/test/quality-route.test.ts @@ -128,6 +128,18 @@ test("a missing, malformed or wrong token is rejected without touching the store } }); +// The padding after "Bearer" is what `\s+(\S` must allow (fetch drops the trailing padding). +test("a whitespace-padded token opens the endpoint", async () => { + const { store } = fakeStore(); + const srv = await serve(qualityRouter(store, { quality_token: TOKEN })); + try { + const res = await srv.get("", { headers: { authorization: `Bearer ${TOKEN} ` } }); + assert.equal(res.status, 200); + } finally { + srv.close(); + } +}); + test("a valid token gets the tally, and the response is never shared-cached", async () => { const { store } = fakeStore(); const srv = await serve(qualityRouter(store, { quality_token: TOKEN }));