From ee96e96bb984cc3e1e152d17199357a8f6db312d Mon Sep 17 00:00:00 2001 From: Xinhua Gu Date: Mon, 9 Mar 2026 19:54:40 +0100 Subject: [PATCH] fix(plugins): strip profileId/preferredProfile from plugin modelAuth wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address Aisle CWE-862: plugins could use profileId to resolve credentials for arbitrary profiles regardless of provider, enabling cross-provider credential access. Now plugins can only specify provider/model — the core auth pipeline picks the appropriate credential. The TypeScript type is also narrowed so plugin authors cannot pass profileId at compile time. --- src/plugins/runtime/index.ts | 14 ++++++-------- src/plugins/runtime/types-core.ts | 12 ++++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/plugins/runtime/index.ts b/src/plugins/runtime/index.ts index 987a3c39700..12d33168cd3 100644 --- a/src/plugins/runtime/index.ts +++ b/src/plugins/runtime/index.ts @@ -64,23 +64,21 @@ export function createPluginRuntime(_options: CreatePluginRuntimeOptions = {}): logging: createRuntimeLogging(), state: { resolveStateDir }, modelAuth: { - // Wrap model-auth helpers to prevent plugins from passing arbitrary - // agentDir / store overrides, which would let them steer credential - // lookups outside their own context. Only provider, model, cfg, and - // profileId are forwarded. + // Wrap model-auth helpers so plugins cannot steer credential lookups: + // - agentDir / store: stripped (prevents reading other agents' stores) + // - profileId / preferredProfile: stripped (prevents cross-provider + // credential access via profile steering) + // Plugins only specify provider/model; the core auth pipeline picks + // the appropriate credential automatically. getApiKeyForModel: (params) => getApiKeyForModelRaw({ model: params.model, cfg: params.cfg, - profileId: params.profileId, - preferredProfile: params.preferredProfile, }), resolveApiKeyForProvider: (params) => resolveApiKeyForProviderRaw({ provider: params.provider, cfg: params.cfg, - profileId: params.profileId, - preferredProfile: params.preferredProfile, }), }, } satisfies PluginRuntime; diff --git a/src/plugins/runtime/types-core.ts b/src/plugins/runtime/types-core.ts index 20dbbd0aaf0..bfbb747c9c4 100644 --- a/src/plugins/runtime/types-core.ts +++ b/src/plugins/runtime/types-core.ts @@ -53,7 +53,15 @@ export type PluginRuntimeCore = { resolveStateDir: typeof import("../../config/paths.js").resolveStateDir; }; modelAuth: { - getApiKeyForModel: typeof import("../../agents/model-auth.js").getApiKeyForModel; - resolveApiKeyForProvider: typeof import("../../agents/model-auth.js").resolveApiKeyForProvider; + /** Resolve auth for a model. Only provider/model and optional cfg are used. */ + getApiKeyForModel: (params: { + model: import("@mariozechner/pi-ai").Model; + cfg?: import("../../config/config.js").OpenClawConfig; + }) => Promise; + /** Resolve auth for a provider by name. Only provider and optional cfg are used. */ + resolveApiKeyForProvider: (params: { + provider: string; + cfg?: import("../../config/config.js").OpenClawConfig; + }) => Promise; }; };