mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-22 07:02:16 +03:00
fix(ssrf): honor local-first provider URL flag in outbound guard (#9123)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- fix(ssrf): make `getProviderOutboundGuard()` (used for search-provider connection validation, image generation and remote image fetch) honor the local-first default `OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS` the same way the chat validation guard already does, so a LAN-hosted SearXNG/Brave search provider works with only the LOCAL flag set instead of silently requiring `OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS` ([#9123](https://github.com/diegosouzapw/OmniRoute/issues/9123)).
|
||||
@@ -56,8 +56,18 @@ export function arePrivateProviderUrlsAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Guard mode for the provider OUTBOUND path (search-provider connection validation, image
|
||||
* generation, remote image fetch, model discovery — anything that does not go through the
|
||||
* chat validation path). Precedence — mirrors `getProviderValidationGuard()` (#9123):
|
||||
* 1. explicit full opt-in (`arePrivateProviderUrlsAllowed`) → "none" (no checks; power users).
|
||||
* 2. local-first default (`areLocalProviderUrlsAllowed`) → "block-metadata" (allow LAN, block IMDS).
|
||||
* 3. otherwise → "public-only" (strict).
|
||||
*/
|
||||
export function getProviderOutboundGuard(): OutboundUrlGuardMode {
|
||||
return arePrivateProviderUrlsAllowed() ? "none" : "public-only";
|
||||
if (arePrivateProviderUrlsAllowed()) return "none";
|
||||
if (areLocalProviderUrlsAllowed()) return "block-metadata";
|
||||
return "public-only";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
49
tests/unit/outbound-url-guard-local-flag.test.ts
Normal file
49
tests/unit/outbound-url-guard-local-flag.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const ENV_KEYS = [
|
||||
"OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS",
|
||||
"OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS",
|
||||
"OUTBOUND_SSRF_GUARD_ENABLED",
|
||||
];
|
||||
|
||||
function withEnv(overrides: Record<string, string | undefined>, fn: () => void) {
|
||||
const saved: Record<string, string | undefined> = {};
|
||||
for (const k of ENV_KEYS) saved[k] = process.env[k];
|
||||
for (const k of ENV_KEYS) delete process.env[k];
|
||||
Object.assign(process.env, overrides);
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
for (const k of ENV_KEYS) {
|
||||
if (saved[k] === undefined) delete process.env[k];
|
||||
else process.env[k] = saved[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("#9123: setting ONLY OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS=true should relax the guard used for search-provider outbound calls (currently does not)", async () => {
|
||||
const { areLocalProviderUrlsAllowed, getProviderOutboundGuard } = await import(
|
||||
"../../src/shared/network/outboundUrlGuardPolicy.ts"
|
||||
);
|
||||
|
||||
withEnv({ OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS: "true" }, () => {
|
||||
assert.equal(areLocalProviderUrlsAllowed(), true);
|
||||
assert.notEqual(
|
||||
getProviderOutboundGuard(),
|
||||
"public-only",
|
||||
"BUG #9123: OMNIROUTE_ALLOW_LOCAL_PROVIDER_URLS should relax getProviderOutboundGuard() " +
|
||||
"(used for search-provider outbound calls) the same way it already relaxes " +
|
||||
"getProviderValidationGuard() for regular chat providers — it currently has no effect."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("#9123 control: OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS=true DOES relax the same guard", async () => {
|
||||
const { getProviderOutboundGuard } = await import(
|
||||
"../../src/shared/network/outboundUrlGuardPolicy.ts"
|
||||
);
|
||||
withEnv({ OMNIROUTE_ALLOW_PRIVATE_PROVIDER_URLS: "true" }, () => {
|
||||
assert.equal(getProviderOutboundGuard(), "none");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user