fix(exec): harden inherited host env sanitization (#25755) (thanks @bmendonca3)

This commit is contained in:
Peter Steinberger
2026-02-24 23:46:29 +00:00
parent 9687f81237
commit 1df084f36b
3 changed files with 30 additions and 2 deletions

View File

@@ -33,10 +33,12 @@ import { getShellConfig, sanitizeBinaryOutput } from "./shell-utils.js";
// are not propagated into non-sandboxed executions.
export function sanitizeHostBaseEnv(env: Record<string, string>): Record<string, string> {
const sanitized: Record<string, string> = {};
let hostPath: string | undefined;
for (const [key, value] of Object.entries(env)) {
const upperKey = key.toUpperCase();
if (upperKey === "PATH") {
sanitized[key] = value;
// Canonicalize PATH casing so downstream PATH merges always hit one key.
hostPath ??= value;
continue;
}
if (isDangerousHostEnvVarName(upperKey)) {
@@ -44,6 +46,9 @@ export function sanitizeHostBaseEnv(env: Record<string, string>): Record<string,
}
sanitized[key] = value;
}
if (hostPath !== undefined) {
sanitized.PATH = hostPath;
}
return sanitized;
}
// Centralized sanitization helper.

View File

@@ -4,6 +4,7 @@ import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { ExecApprovalsResolved } from "../infra/exec-approvals.js";
import { captureEnv } from "../test-utils/env.js";
import { sanitizeHostBaseEnv } from "./bash-tools.exec-runtime.js";
import { sanitizeBinaryOutput } from "./shell-utils.js";
const isWin = process.platform === "win32";
@@ -155,6 +156,28 @@ describe("exec PATH login shell merge", () => {
});
describe("exec host env validation", () => {
it("sanitizes inherited host env without mutating source object", () => {
const inherited = {
PATH: "/usr/bin",
Path: "/should-not-win",
SAFE_KEY: "ok",
LD_PRELOAD: "bad",
sslkeylogfile: "/tmp/keys.log",
};
const sanitized = sanitizeHostBaseEnv(inherited);
expect(sanitized).toEqual({
PATH: "/usr/bin",
SAFE_KEY: "ok",
});
expect(inherited).toEqual({
PATH: "/usr/bin",
Path: "/should-not-win",
SAFE_KEY: "ok",
LD_PRELOAD: "bad",
sslkeylogfile: "/tmp/keys.log",
});
});
it("blocks LD_/DYLD_ env vars on host execution", async () => {
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });