From 84a50acb5531eb7d6a0278f4aae44a7ceea797d1 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 13 Mar 2026 21:11:34 +0000 Subject: [PATCH] refactor: share portable env entry normalization --- src/infra/host-env-security.ts | 43 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/infra/host-env-security.ts b/src/infra/host-env-security.ts index 8c5d0989fdd..11d6b8e9f3c 100644 --- a/src/infra/host-env-security.ts +++ b/src/infra/host-env-security.ts @@ -80,6 +80,23 @@ export function isDangerousHostEnvOverrideVarName(rawKey: string): boolean { return HOST_DANGEROUS_OVERRIDE_ENV_PREFIXES.some((prefix) => upper.startsWith(prefix)); } +function listNormalizedPortableEnvEntries( + source: Record, +): Array<[string, string]> { + const entries: Array<[string, string]> = []; + for (const [rawKey, value] of Object.entries(source)) { + if (typeof value !== "string") { + continue; + } + const key = normalizeEnvVarKey(rawKey, { portable: true }); + if (!key) { + continue; + } + entries.push([key, value]); + } + return entries; +} + export function sanitizeHostExecEnv(params?: { baseEnv?: Record; overrides?: Record | null; @@ -90,12 +107,8 @@ export function sanitizeHostExecEnv(params?: { const blockPathOverrides = params?.blockPathOverrides ?? true; const merged: Record = {}; - for (const [rawKey, value] of Object.entries(baseEnv)) { - if (typeof value !== "string") { - continue; - } - const key = normalizeEnvVarKey(rawKey, { portable: true }); - if (!key || isDangerousHostEnvVarName(key)) { + for (const [key, value] of listNormalizedPortableEnvEntries(baseEnv)) { + if (isDangerousHostEnvVarName(key)) { continue; } merged[key] = value; @@ -105,14 +118,7 @@ export function sanitizeHostExecEnv(params?: { return markOpenClawExecEnv(merged); } - for (const [rawKey, value] of Object.entries(overrides)) { - if (typeof value !== "string") { - continue; - } - const key = normalizeEnvVarKey(rawKey, { portable: true }); - if (!key) { - continue; - } + for (const [key, value] of listNormalizedPortableEnvEntries(overrides)) { const upper = key.toUpperCase(); // PATH is part of the security boundary (command resolution + safe-bin checks). Never allow // request-scoped PATH overrides from agents/gateways. @@ -140,14 +146,7 @@ export function sanitizeSystemRunEnvOverrides(params?: { return overrides; } const filtered: Record = {}; - for (const [rawKey, value] of Object.entries(overrides)) { - if (typeof value !== "string") { - continue; - } - const key = normalizeEnvVarKey(rawKey, { portable: true }); - if (!key) { - continue; - } + for (const [key, value] of listNormalizedPortableEnvEntries(overrides)) { if (!HOST_SHELL_WRAPPER_ALLOWED_OVERRIDE_ENV_KEYS.has(key.toUpperCase())) { continue; }