From 02362e1467123035945d2bb1c88e6a0e21df7276 Mon Sep 17 00:00:00 2001 From: Charan Rathore <180254320+charan-rathore@users.noreply.github.com> Date: Thu, 1 Oct 2026 19:42:15 +0530 Subject: [PATCH] Ignore inherited provider and Bot registry entries --- CHANGELOG.md | 6 ++++++ shared/model-providers.test.ts | 15 +++++++++++++++ shared/model-providers.ts | 8 ++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 296cb10ed..3b835932d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,12 @@ refused in every mode, including `allow_all`, and the browser's WebRTC traffic n filter instead of around it. A computer run without an API server can set `EGRESS_POLICY_REQUIRED=0` to keep the old behaviour. +### Provider and Bot lookups ignore inherited object properties + +Unknown names such as `constructor` and `__proto__` no longer return an inherited +JavaScript object as a provider or Bot entry. Unknown providers return no spec, and +missing Bots raise the existing startup error. Configured providers and Bots are unchanged. + ### `start.sh` names the port to change on macOS When the API server's or the app's port was held by another process, `start.sh` was meant to say diff --git a/shared/model-providers.test.ts b/shared/model-providers.test.ts index 6f42fde3e..ac71102fe 100644 --- a/shared/model-providers.test.ts +++ b/shared/model-providers.test.ts @@ -319,3 +319,18 @@ describe("what a Bot runs from the spec file", () => { ); }); }); + +describe("registry lookups ignore inherited object properties", () => { + test("prototype names are not providers", () => { + for (const name of ["constructor", "__proto__", "toString", "valueOf"]) { + expect(providerSpec(name)).toBeUndefined(); + expect(keyVariableFor(name)).toBeUndefined(); + expect(baseUrlVariableFor(name)).toBeUndefined(); + } + }); + test("prototype names are not Bot entries", () => { + for (const name of ["constructor", "__proto__", "toString", "valueOf"]) { + expect(() => botSettings(name, {})).toThrow(`bots has no ${name} entry`); + } + }); +}); diff --git a/shared/model-providers.ts b/shared/model-providers.ts index ab1ca34dd..ac7a7aa70 100644 --- a/shared/model-providers.ts +++ b/shared/model-providers.ts @@ -166,7 +166,9 @@ export function providerSpec( provider: string | undefined, ): ProviderSpec | undefined { const normalized = provider?.trim().toLowerCase() || "openai"; - return MODEL_PROVIDERS[normalized as ModelProviderId]; + return Object.hasOwn(MODEL_PROVIDERS, normalized) + ? MODEL_PROVIDERS[normalized as ModelProviderId] + : undefined; } /** The environment variable this provider's key arrives in, or nothing for a provider unknown. */ @@ -248,7 +250,9 @@ export function botSettings( env: Readonly> = process.env, pinnedProvider?: string, ): BotSettings { - const entry = BOT_ENTRIES[botId]; + const entry = Object.hasOwn(BOT_ENTRIES, botId) + ? BOT_ENTRIES[botId] + : undefined; if (!entry) { fail( `bots has no ${botId} entry. Add one before this Bot reads the spec file.`,