Files
OmniRoute/tests/unit/providers-autosync-ssrf-323.test.ts
Diego Rodrigues de Sa e Souza df2379053e fix(security): use trusted internal origin for provider auto-sync self-fetch (CodeQL #323 SSRF) (#3336)
POST /api/providers fires a credential-bearing self-fetch to the new
connection's /sync-models route (forwarding the management cookie + internal
sync auth headers). #3267 built that origin from new URL(request.url).origin —
the client-controlled Host header — so a (management-authenticated) caller
could redirect the internal request to an arbitrary host, exfiltrating the
internal sync auth token (CodeQL js/request-forgery, critical, alert #323).

Derive the origin from the trusted loopback/env-pinned base URL via a new
getModelSyncInternalBaseUrl() helper (same source the model-sync scheduler
already uses), never from the incoming request. Adds a regression test.
2026-06-06 21:20:26 -03:00

36 lines
1.4 KiB
TypeScript

/**
* Regression guard — CodeQL js/request-forgery alert #323 (v3.8.13).
*
* POST /api/providers fires a non-blocking self-fetch to the connection's
* /sync-models route, forwarding the management cookie + internal sync auth
* headers. #3267 built that self-fetch origin from `new URL(request.url).origin`
* — i.e. the client-controlled Host header — so a caller could redirect the
* credential-bearing internal request to an arbitrary host (SSRF + internal
* auth-header exfiltration).
*
* The origin must come from the trusted loopback/env-pinned base URL
* (`getModelSyncInternalBaseUrl()`), never from the incoming request.
*/
import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { join } from "node:path";
const routeSrc = readFileSync(
join(import.meta.dirname, "../../src/app/api/providers/route.ts"),
"utf8"
);
test("POST /api/providers auto-sync uses the trusted internal origin (not request.url) — #323", () => {
assert.ok(
routeSrc.includes("getModelSyncInternalBaseUrl()"),
"auto-sync self-fetch must derive its origin from getModelSyncInternalBaseUrl()"
);
assert.doesNotMatch(
routeSrc,
/const\s+internalOrigin\s*=\s*new URL\(request\.url\)\.origin/,
"auto-sync origin must NOT be derived from the client-controlled request.url/Host (SSRF, CodeQL js/request-forgery #323)"
);
});