Security: sanitize inherited host exec env
This commit is contained in:
committed by
Peter Steinberger
parent
9514201fb9
commit
48b052322b
@@ -29,6 +29,23 @@ import {
|
||||
import { buildCursorPositionResponse, stripDsrRequests } from "./pty-dsr.js";
|
||||
import { getShellConfig, sanitizeBinaryOutput } from "./shell-utils.js";
|
||||
|
||||
// Sanitize inherited host env before merge so dangerous variables from process.env
|
||||
// are not propagated into non-sandboxed executions.
|
||||
export function sanitizeHostBaseEnv(env: Record<string, string>): Record<string, string> {
|
||||
const sanitized: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
const upperKey = key.toUpperCase();
|
||||
if (upperKey === "PATH") {
|
||||
sanitized[key] = value;
|
||||
continue;
|
||||
}
|
||||
if (isDangerousHostEnvVarName(upperKey)) {
|
||||
continue;
|
||||
}
|
||||
sanitized[key] = value;
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
// Centralized sanitization helper.
|
||||
// Throws an error if dangerous variables or PATH modifications are detected on the host.
|
||||
export function validateHostEnv(env: Record<string, string>): void {
|
||||
|
||||
@@ -166,6 +166,29 @@ describe("exec host env validation", () => {
|
||||
).rejects.toThrow(/Security Violation: Environment variable 'LD_DEBUG' is forbidden/);
|
||||
});
|
||||
|
||||
it("strips dangerous inherited env vars from host execution", async () => {
|
||||
if (isWin) {
|
||||
return;
|
||||
}
|
||||
const original = process.env.SSLKEYLOGFILE;
|
||||
process.env.SSLKEYLOGFILE = "/tmp/openclaw-ssl-keys.log";
|
||||
try {
|
||||
const { createExecTool } = await import("./bash-tools.exec.js");
|
||||
const tool = createExecTool({ host: "gateway", security: "full", ask: "off" });
|
||||
const result = await tool.execute("call1", {
|
||||
command: "printf '%s' \"${SSLKEYLOGFILE:-}\"",
|
||||
});
|
||||
const output = normalizeText(result.content.find((c) => c.type === "text")?.text);
|
||||
expect(output).not.toContain("/tmp/openclaw-ssl-keys.log");
|
||||
} finally {
|
||||
if (original === undefined) {
|
||||
delete process.env.SSLKEYLOGFILE;
|
||||
} else {
|
||||
process.env.SSLKEYLOGFILE = original;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("defaults to sandbox when sandbox runtime is unavailable", async () => {
|
||||
const tool = createExecTool({ security: "full", ask: "off" });
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
renderExecHostLabel,
|
||||
resolveApprovalRunningNoticeMs,
|
||||
runExecProcess,
|
||||
sanitizeHostBaseEnv,
|
||||
execSchema,
|
||||
validateHostEnv,
|
||||
} from "./bash-tools.exec-runtime.js";
|
||||
@@ -359,7 +360,8 @@ export function createExecTool(
|
||||
workdir = resolveWorkdir(rawWorkdir, warnings);
|
||||
}
|
||||
|
||||
const baseEnv = coerceEnv(process.env);
|
||||
const inheritedBaseEnv = coerceEnv(process.env);
|
||||
const baseEnv = host === "sandbox" ? inheritedBaseEnv : sanitizeHostBaseEnv(inheritedBaseEnv);
|
||||
|
||||
// Logic: Sandbox gets raw env. Host (gateway/node) must pass validation.
|
||||
// We validate BEFORE merging to prevent any dangerous vars from entering the stream.
|
||||
|
||||
Reference in New Issue
Block a user