|
|
|
|
@@ -143,10 +143,14 @@ describe("isDangerousHostEnvVarName", () => {
|
|
|
|
|
expect(isDangerousHostEnvVarName("cxx")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("CARGO_BUILD_RUSTC")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("cargo_build_rustc")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("CARGO_BUILD_RUSTC_WRAPPER")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("cargo_build_rustc_wrapper")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("CMAKE_C_COMPILER")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("cmake_c_compiler")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("CMAKE_CXX_COMPILER")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("cmake_cxx_compiler")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("RUSTC_WRAPPER")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("rustc_wrapper")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("SHELLOPTS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("ps4")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("DYLD_INSERT_LIBRARIES")).toBe(true);
|
|
|
|
|
@@ -168,12 +172,18 @@ describe("isDangerousHostEnvVarName", () => {
|
|
|
|
|
expect(isDangerousHostEnvVarName("glibc_tunables")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("MAVEN_OPTS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("maven_opts")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("MAKEFLAGS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("makeflags")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("MFLAGS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("mflags")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("SBT_OPTS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("sbt_opts")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("GRADLE_OPTS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("gradle_opts")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("ANT_OPTS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("ant_opts")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("HGRCPATH")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("hgrcpath")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvVarName("HTTPS_PROXY")).toBe(false);
|
|
|
|
|
expect(isDangerousHostEnvVarName("https_proxy")).toBe(false);
|
|
|
|
|
expect(isDangerousHostEnvVarName("HTTP_PROXY")).toBe(false);
|
|
|
|
|
@@ -210,6 +220,11 @@ describe("sanitizeHostExecEnv", () => {
|
|
|
|
|
GIT_EXTERNAL_DIFF: "/tmp/pwn.sh",
|
|
|
|
|
GIT_TEMPLATE_DIR: "/tmp/git-template",
|
|
|
|
|
GIT_SEQUENCE_EDITOR: "/tmp/pwn-sequence-editor",
|
|
|
|
|
HGRCPATH: "/tmp/evil-hgrc",
|
|
|
|
|
CARGO_BUILD_RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
|
|
|
|
RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
|
|
|
|
MAKEFLAGS: "--eval=$(shell touch /tmp/pwned)",
|
|
|
|
|
MFLAGS: "--eval=$(shell touch /tmp/pwned-too)",
|
|
|
|
|
AWS_CONFIG_FILE: "/tmp/aws-config",
|
|
|
|
|
LD_PRELOAD: "/tmp/pwn.so",
|
|
|
|
|
OK: "1",
|
|
|
|
|
@@ -242,8 +257,11 @@ describe("sanitizeHostExecEnv", () => {
|
|
|
|
|
CC: "/tmp/evil-cc",
|
|
|
|
|
CXX: "/tmp/evil-cxx",
|
|
|
|
|
CARGO_BUILD_RUSTC: "/tmp/evil-rustc",
|
|
|
|
|
CARGO_BUILD_RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
|
|
|
|
CMAKE_C_COMPILER: "/tmp/evil-c-compiler",
|
|
|
|
|
CMAKE_CXX_COMPILER: "/tmp/evil-cxx-compiler",
|
|
|
|
|
RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
|
|
|
|
HGRCPATH: "/tmp/evil-hgrc",
|
|
|
|
|
GIT_SSH_COMMAND: "touch /tmp/pwned",
|
|
|
|
|
GIT_EDITOR: "/tmp/git-editor",
|
|
|
|
|
GIT_EXEC_PATH: "/tmp/git-exec-path",
|
|
|
|
|
@@ -295,6 +313,8 @@ describe("sanitizeHostExecEnv", () => {
|
|
|
|
|
PS4: "$(touch /tmp/pwned)",
|
|
|
|
|
CLASSPATH: "/tmp/evil-classpath",
|
|
|
|
|
GOFLAGS: "-mod=mod",
|
|
|
|
|
MAKEFLAGS: "--eval=$(shell touch /tmp/pwned)",
|
|
|
|
|
MFLAGS: "--eval=$(shell touch /tmp/pwned-too)",
|
|
|
|
|
PHPRC: "/tmp/evil-php.ini",
|
|
|
|
|
XDG_CONFIG_HOME: "/tmp/evil-config",
|
|
|
|
|
SAFE: "ok",
|
|
|
|
|
@@ -309,8 +329,11 @@ describe("sanitizeHostExecEnv", () => {
|
|
|
|
|
expect(env.CC).toBeUndefined();
|
|
|
|
|
expect(env.CXX).toBeUndefined();
|
|
|
|
|
expect(env.CARGO_BUILD_RUSTC).toBeUndefined();
|
|
|
|
|
expect(env.CARGO_BUILD_RUSTC_WRAPPER).toBeUndefined();
|
|
|
|
|
expect(env.CMAKE_C_COMPILER).toBeUndefined();
|
|
|
|
|
expect(env.CMAKE_CXX_COMPILER).toBeUndefined();
|
|
|
|
|
expect(env.RUSTC_WRAPPER).toBeUndefined();
|
|
|
|
|
expect(env.HGRCPATH).toBeUndefined();
|
|
|
|
|
expect(env.GIT_TEMPLATE_DIR).toBeUndefined();
|
|
|
|
|
expect(env.GIT_SEQUENCE_EDITOR).toBeUndefined();
|
|
|
|
|
expect(env.AWS_CONFIG_FILE).toBeUndefined();
|
|
|
|
|
@@ -324,6 +347,8 @@ describe("sanitizeHostExecEnv", () => {
|
|
|
|
|
expect(env.PS4).toBeUndefined();
|
|
|
|
|
expect(env.CLASSPATH).toBeUndefined();
|
|
|
|
|
expect(env.GOFLAGS).toBeUndefined();
|
|
|
|
|
expect(env.MAKEFLAGS).toBeUndefined();
|
|
|
|
|
expect(env.MFLAGS).toBeUndefined();
|
|
|
|
|
expect(env.PHPRC).toBeUndefined();
|
|
|
|
|
expect(env.XDG_CONFIG_HOME).toBeUndefined();
|
|
|
|
|
expect(env.YARN_RC_FILENAME).toBe(".trusted-yarnrc.yml");
|
|
|
|
|
@@ -524,8 +549,18 @@ describe("isDangerousHostEnvOverrideVarName", () => {
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("virtual_env")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("CLASSPATH")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("classpath")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("MAKEFLAGS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("makeflags")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("MFLAGS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("mflags")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("GOFLAGS")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("goflags")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("HGRCPATH")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("hgrcpath")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("RUSTC_WRAPPER")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("rustc_wrapper")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("CARGO_BUILD_RUSTC_WRAPPER")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("cargo_build_rustc_wrapper")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("CORECLR_PROFILER_PATH")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("coreclr_profiler_path")).toBe(true);
|
|
|
|
|
expect(isDangerousHostEnvOverrideVarName("XDG_CONFIG_HOME")).toBe(true);
|
|
|
|
|
@@ -547,6 +582,7 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
overrides: {
|
|
|
|
|
PATH: "/tmp/evil",
|
|
|
|
|
CXX: "/tmp/evil-cxx",
|
|
|
|
|
CARGO_BUILD_RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
|
|
|
|
CARGO_REGISTRIES_CRATES_IO_INDEX: "https://example.invalid/crates.io-index",
|
|
|
|
|
CMAKE_C_COMPILER: "/tmp/evil-c-compiler",
|
|
|
|
|
CLASSPATH: "/tmp/evil-classpath",
|
|
|
|
|
@@ -582,7 +618,11 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
GOPRIVATE: "example.invalid/*",
|
|
|
|
|
GOENV: "/tmp/evil-goenv",
|
|
|
|
|
GOPATH: "/tmp/evil-go",
|
|
|
|
|
HGRCPATH: "/tmp/evil-hgrc",
|
|
|
|
|
MAKEFLAGS: "--eval=$(shell touch /tmp/pwned)",
|
|
|
|
|
MFLAGS: "--eval=$(shell touch /tmp/pwned-too)",
|
|
|
|
|
PYTHONUSERBASE: "/tmp/evil-python-userbase",
|
|
|
|
|
RUSTC_WRAPPER: "/tmp/evil-rustc-wrapper",
|
|
|
|
|
VIRTUAL_ENV: "/tmp/evil-venv",
|
|
|
|
|
YARN_RC_FILENAME: ".evil-yarnrc.yml",
|
|
|
|
|
HTTPS_PROXY: "http://proxy.example.test:8080",
|
|
|
|
|
@@ -597,6 +637,7 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
|
|
|
|
|
expect(result.rejectedOverrideBlockedKeys).toEqual([
|
|
|
|
|
"C_INCLUDE_PATH",
|
|
|
|
|
"CARGO_BUILD_RUSTC_WRAPPER",
|
|
|
|
|
"CARGO_REGISTRIES_CRATES_IO_INDEX",
|
|
|
|
|
"CLASSPATH",
|
|
|
|
|
"CMAKE_C_COMPILER",
|
|
|
|
|
@@ -618,8 +659,11 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
"GOPATH",
|
|
|
|
|
"GOPRIVATE",
|
|
|
|
|
"GOPROXY",
|
|
|
|
|
"HGRCPATH",
|
|
|
|
|
"HTTPS_PROXY",
|
|
|
|
|
"LIBRARY_PATH",
|
|
|
|
|
"MAKEFLAGS",
|
|
|
|
|
"MFLAGS",
|
|
|
|
|
"NODE_EXTRA_CA_CERTS",
|
|
|
|
|
"NODE_TLS_REJECT_UNAUTHORIZED",
|
|
|
|
|
"OBJC_INCLUDE_PATH",
|
|
|
|
|
@@ -632,6 +676,7 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
"PIP_TRUSTED_HOST",
|
|
|
|
|
"PYTHONUSERBASE",
|
|
|
|
|
"REQUESTS_CA_BUNDLE",
|
|
|
|
|
"RUSTC_WRAPPER",
|
|
|
|
|
"SSL_CERT_DIR",
|
|
|
|
|
"SSL_CERT_FILE",
|
|
|
|
|
"UV_DEFAULT_INDEX",
|
|
|
|
|
@@ -648,6 +693,7 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
expect(result.env.CLASSPATH).toBeUndefined();
|
|
|
|
|
expect(result.env.CXX).toBeUndefined();
|
|
|
|
|
expect(result.env.CMAKE_C_COMPILER).toBeUndefined();
|
|
|
|
|
expect(result.env.CARGO_BUILD_RUSTC_WRAPPER).toBeUndefined();
|
|
|
|
|
expect(result.env.CARGO_REGISTRIES_CRATES_IO_INDEX).toBeUndefined();
|
|
|
|
|
expect(result.env.PIP_INDEX_URL).toBeUndefined();
|
|
|
|
|
expect(result.env.PIP_PYPI_URL).toBeUndefined();
|
|
|
|
|
@@ -684,9 +730,13 @@ describe("sanitizeHostExecEnvWithDiagnostics", () => {
|
|
|
|
|
expect(result.env.GOPRIVATE).toBeUndefined();
|
|
|
|
|
expect(result.env.GOENV).toBeUndefined();
|
|
|
|
|
expect(result.env.GOPATH).toBeUndefined();
|
|
|
|
|
expect(result.env.HGRCPATH).toBeUndefined();
|
|
|
|
|
expect(result.env.HTTPS_PROXY).toBeUndefined();
|
|
|
|
|
expect(result.env.MAKEFLAGS).toBeUndefined();
|
|
|
|
|
expect(result.env.MFLAGS).toBeUndefined();
|
|
|
|
|
expect(result.env.NODE_TLS_REJECT_UNAUTHORIZED).toBeUndefined();
|
|
|
|
|
expect(result.env.PYTHONUSERBASE).toBeUndefined();
|
|
|
|
|
expect(result.env.RUSTC_WRAPPER).toBeUndefined();
|
|
|
|
|
expect(result.env.VIRTUAL_ENV).toBeUndefined();
|
|
|
|
|
expect(result.env.YARN_RC_FILENAME).toBeUndefined();
|
|
|
|
|
});
|
|
|
|
|
@@ -1100,3 +1150,52 @@ describe("compiler override exploit regression", () => {
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("make env exploit regression", () => {
|
|
|
|
|
it("blocks MAKEFLAGS overrides so make cannot evaluate shell payloads from env", async () => {
|
|
|
|
|
const makePath = getSystemMakePath();
|
|
|
|
|
if (!makePath) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const tempDir = fs.mkdtempSync(
|
|
|
|
|
path.join(os.tmpdir(), `openclaw-makeflags-override-${process.pid}-${Date.now()}-`),
|
|
|
|
|
);
|
|
|
|
|
const exploitPath = path.join(tempDir, "evil-makeflags.sh");
|
|
|
|
|
const marker = path.join(os.tmpdir(), `openclaw-makeflags-marker-${process.pid}-${Date.now()}`);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
clearMarker(marker);
|
|
|
|
|
fs.writeFileSync(path.join(tempDir, "Makefile"), "all:\n\t@:\n", "utf8");
|
|
|
|
|
fs.writeFileSync(exploitPath, `#!/bin/sh\ntouch ${JSON.stringify(marker)}\n`, "utf8");
|
|
|
|
|
fs.chmodSync(exploitPath, 0o755);
|
|
|
|
|
|
|
|
|
|
const exploitValue = `--eval=$(shell ${exploitPath})`;
|
|
|
|
|
const baseEnv = {
|
|
|
|
|
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await runMakeCommand(makePath, tempDir, {
|
|
|
|
|
...baseEnv,
|
|
|
|
|
MAKEFLAGS: exploitValue,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
expect(fs.existsSync(marker)).toBe(true);
|
|
|
|
|
clearMarker(marker);
|
|
|
|
|
|
|
|
|
|
const safeEnv = sanitizeHostExecEnv({
|
|
|
|
|
baseEnv,
|
|
|
|
|
overrides: {
|
|
|
|
|
MAKEFLAGS: exploitValue,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await runMakeCommand(makePath, tempDir, safeEnv);
|
|
|
|
|
|
|
|
|
|
expect(fs.existsSync(marker)).toBe(false);
|
|
|
|
|
} finally {
|
|
|
|
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
|
|
|
fs.rmSync(marker, { force: true });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|