mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-24 08:02:14 +03:00
Validated on a 2-PR combined board: routeGuard 36/36 (within the 68/68 focused-file total), a2a-task-owner-idor 7/7, a2a-tasks-auth, search-baseurl-ssrf-guard, cli-serve-hostname, spawn-capable-prefixes-client-safe all green, typecheck:core + dashboard-typecheck clean, gates within baseline. Five real High-severity advisories fixed with TDD (each failing-then-passing): settings export/import-json ALWAYS_PROTECTED completion, MITM route LOCAL_ONLY+SPAWN_CAPABLE gating, search baseUrl SSRF/IMDS guard, A2A REST task auth+ownership (previously none at all), and the loud boot exposure warning. GHSA-cjv9 confirmed already closed on this base (verified). Round 3 of the advisory sweep.
58 lines
2.3 KiB
JavaScript
58 lines
2.3 KiB
JavaScript
import { hostname, platform } from "node:os";
|
|
|
|
/**
|
|
* Resolve the bind host passed to the standalone Next.js server.
|
|
*
|
|
* HOSTNAME is a standard shell variable on Unix-like systems, so only the
|
|
* dedicated OmniRoute variable is treated as configuration there. Windows
|
|
* keeps the legacy HOSTNAME fallback for compatibility with existing .env
|
|
* files, while still ignoring the OS-reported machine name.
|
|
*
|
|
* @param {NodeJS.ProcessEnv} [env]
|
|
* @param {NodeJS.Platform} [runtimePlatform]
|
|
* @param {string} [machineHostname]
|
|
* @returns {string}
|
|
*/
|
|
export function resolveServerHost(
|
|
env = process.env,
|
|
runtimePlatform = platform(),
|
|
machineHostname = hostname()
|
|
) {
|
|
if (env.OMNIROUTE_SERVER_HOST) return env.OMNIROUTE_SERVER_HOST;
|
|
if (runtimePlatform === "win32" && env.HOSTNAME && env.HOSTNAME !== machineHostname) {
|
|
return env.HOSTNAME;
|
|
}
|
|
return "0.0.0.0";
|
|
}
|
|
|
|
const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
|
|
|
|
/**
|
|
* Boot-time exposure warning (GHSA-wmgv-ph3p-rv57): the shipped default binds
|
|
* all interfaces while the inference plane requires no credentials, so any
|
|
* LAN peer can spend the operator's quota. That local-first posture is a
|
|
* deliberate, documented default — but it must be LOUD at startup so an
|
|
* operator who never read the docs still learns the two escape hatches.
|
|
*
|
|
* Returns the warning text when the server will listen on a non-loopback
|
|
* interface with no API-key requirement, or null when the exposure is closed.
|
|
*
|
|
* @param {NodeJS.ProcessEnv} [env]
|
|
* @param {string} [host]
|
|
* @returns {string | null}
|
|
*/
|
|
export function resolveExposureWarning(env = process.env, host = resolveServerHost(env)) {
|
|
if (LOOPBACK_HOSTS.has(host)) return null;
|
|
const requireKey = String(env.REQUIRE_API_KEY || "")
|
|
.trim()
|
|
.toLowerCase();
|
|
if (requireKey === "true" || requireKey === "1" || requireKey === "yes") return null;
|
|
return (
|
|
`SECURITY: listening on ${host} with NO API-key requirement — the inference ` +
|
|
`plane (/v1/*) is reachable by ANY device that can route to this host, and ` +
|
|
`requests are billed to your configured providers. This local-first default ` +
|
|
`is intentional, but on an untrusted network either set REQUIRE_API_KEY=true ` +
|
|
`or bind loopback with OMNIROUTE_SERVER_HOST=127.0.0.1.`
|
|
);
|
|
}
|