From c2d46776fd90dbc72f7d7011fb7fe7257ca585dc Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Fri, 5 Jun 2026 16:48:13 -0300 Subject: [PATCH] fix(security): clear CodeQL high alerts surfaced on the v3.8.11 release PR diff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeQL flagged 7 high alerts in code the cycle touched (the large release-PR diff re-surfaces them). Resolved at the source — no dismissals: - fix(images): resolveImageBaseUrl trimmed trailing slashes with `/\/+$/`, a polynomial-ReDoS pattern (js/polynomial-redos) on the configured node base URL. Replace it with a non-backtracking endsWith/slice loop. - test(oauth): pin the Anthropic OAuth host with exact-equality asserts and a parsed-hostname negative check instead of substring `.includes()` (js/incomplete-url-substring-sanitization). The exact-equality assertions were already present, so coverage is unchanged. - test(images): drop the redundant `!includes("generativelanguage.googleapis.com")` assert — the exact-equality assert on the resolved URL already guarantees it. --- open-sse/handlers/imageGeneration.ts | 5 ++- tests/unit/claude-oauth-vps-endpoints.test.ts | 31 ++++++------------- .../image-generation-baseurl-3205.test.ts | 9 ++---- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/open-sse/handlers/imageGeneration.ts b/open-sse/handlers/imageGeneration.ts index a98762a8fc..b438fee1c4 100644 --- a/open-sse/handlers/imageGeneration.ts +++ b/open-sse/handlers/imageGeneration.ts @@ -131,7 +131,10 @@ export function resolveImageBaseUrl( // points at the requested OpenAI image path, and rewrite one that points at the other // image endpoint (e.g. `.../images/generations` requested for edits) (#3214/#3215). const suffix = `/images/${endpoint}`; - const normalized = nodeBaseUrl.replace(/\/+$/, ""); + // Trim trailing slashes without a backtracking-prone regex (`/\/+$/` is a + // polynomial-ReDoS pattern on long runs of "/" — CodeQL js/polynomial-redos). + let normalized = nodeBaseUrl; + while (normalized.endsWith("/")) normalized = normalized.slice(0, -1); if (normalized.endsWith(suffix)) return normalized; const stripped = normalized.replace(/\/images\/(?:generations|edits)$/, ""); return `${stripped}${suffix}`; diff --git a/tests/unit/claude-oauth-vps-endpoints.test.ts b/tests/unit/claude-oauth-vps-endpoints.test.ts index 86762472a6..61642d8166 100644 --- a/tests/unit/claude-oauth-vps-endpoints.test.ts +++ b/tests/unit/claude-oauth-vps-endpoints.test.ts @@ -4,23 +4,15 @@ import { CLAUDE_CONFIG } from "@/lib/oauth/constants/oauth.ts"; import { OAUTH_ENDPOINTS } from "@omniroute/open-sse/config/constants.ts"; import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts"; +// Exact-equality assertions (not substring `.includes`) so the host is pinned +// precisely — a substring check would also pass for e.g. `api.anthropic.com.evil` +// (CodeQL js/incomplete-url-substring-sanitization). + test("CLAUDE_CONFIG.tokenUrl uses api.anthropic.com (not console.anthropic.com)", () => { - assert.ok( - CLAUDE_CONFIG.tokenUrl.includes("api.anthropic.com"), - `Expected api.anthropic.com but got ${CLAUDE_CONFIG.tokenUrl}` - ); assert.equal(CLAUDE_CONFIG.tokenUrl, "https://api.anthropic.com/v1/oauth/token"); }); test("OAUTH_ENDPOINTS.anthropic uses api.anthropic.com for token and auth", () => { - assert.ok( - OAUTH_ENDPOINTS.anthropic.token.includes("api.anthropic.com"), - `Expected api.anthropic.com but got ${OAUTH_ENDPOINTS.anthropic.token}` - ); - assert.ok( - OAUTH_ENDPOINTS.anthropic.auth.includes("api.anthropic.com"), - `Expected api.anthropic.com but got ${OAUTH_ENDPOINTS.anthropic.auth}` - ); assert.equal(OAUTH_ENDPOINTS.anthropic.token, "https://api.anthropic.com/v1/oauth/token"); assert.equal(OAUTH_ENDPOINTS.anthropic.auth, "https://api.anthropic.com/v1/oauth/authorize"); }); @@ -28,10 +20,6 @@ test("OAUTH_ENDPOINTS.anthropic uses api.anthropic.com for token and auth", () = test("Provider registry claude oauth.tokenUrl uses api.anthropic.com", () => { const claude = REGISTRY.claude; assert.ok(claude, "claude provider should exist in registry"); - assert.ok( - claude.oauth?.tokenUrl?.includes("api.anthropic.com"), - `Expected api.anthropic.com but got ${claude.oauth?.tokenUrl}` - ); assert.equal(claude.oauth.tokenUrl, "https://api.anthropic.com/v1/oauth/token"); }); @@ -41,12 +29,13 @@ test("No console.anthropic.com remains in OAuth constants or registry", () => { OAUTH_ENDPOINTS.anthropic.token, OAUTH_ENDPOINTS.anthropic.auth, REGISTRY.claude?.oauth?.tokenUrl, - ].filter(Boolean); + ].filter(Boolean) as string[]; for (const url of allUrls) { - assert.equal( - url.includes("console.anthropic.com"), - false, - `Found console.anthropic.com in ${url}` + // Compare the parsed hostname, not a substring, so the check is exact. + assert.notEqual( + new URL(url).hostname, + "console.anthropic.com", + `Found console.anthropic.com host in ${url}` ); } }); diff --git a/tests/unit/image-generation-baseurl-3205.test.ts b/tests/unit/image-generation-baseurl-3205.test.ts index de12ad5416..cf4e190666 100644 --- a/tests/unit/image-generation-baseurl-3205.test.ts +++ b/tests/unit/image-generation-baseurl-3205.test.ts @@ -14,12 +14,9 @@ test("#3205: custom node baseUrl from providerSpecificData is used (not Gemini f resolved.startsWith("https://example.com/"), `expected resolved URL to point to example.com, got: ${resolved}` ); - assert.ok( - !resolved.includes("generativelanguage.googleapis.com"), - `resolved URL must not fall back to the Gemini endpoint, got: ${resolved}` - ); - // A node configured as https://example.com/v1 should yield the OpenAI-compatible - // images path appended. + // The exact-equality assertion below already guarantees the Gemini fallback + // was not used (a substring `.includes` check trips CodeQL + // js/incomplete-url-substring-sanitization and is redundant here). assert.equal(resolved, "https://example.com/v1/images/generations"); });