VYPR
Medium severity5.3NVD Advisory· Published Apr 23, 2026· Updated Apr 29, 2026

CVE-2026-41332

CVE-2026-41332

Description

OpenClaw before 2026.3.28 contains an environment variable sanitization vulnerability where GIT_TEMPLATE_DIR and AWS_CONFIG_FILE are not blocked in the host-env blocklist. Attackers can exploit approved exec requests to redirect git or AWS CLI behavior through attacker-controlled configuration files to execute untrusted code or load malicious credentials.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.282026.3.28

Affected products

1
  • cpe:2.3:a:openclaw:openclaw:*:*:*:*:*:node.js:*:*
    Range: <2026.3.28

Patches

1
6eb82fba3cbf

Infra: block additional host exec env keys (#55977)

https://github.com/openclaw/openclawJacob TomlinsonMar 27, 2026via ghsa
3 files changed · +127 2
  • apps/macos/Sources/OpenClaw/HostEnvSecurityPolicy.generated.swift+3 1 modified
    @@ -18,6 +18,7 @@ enum HostEnvSecurityPolicy {
             "ENV",
             "GIT_EXTERNAL_DIFF",
             "GIT_EXEC_PATH",
    +        "GIT_TEMPLATE_DIR",
             "SHELL",
             "SHELLOPTS",
             "PS4",
    @@ -34,7 +35,8 @@ enum HostEnvSecurityPolicy {
             "MAVEN_OPTS",
             "SBT_OPTS",
             "GRADLE_OPTS",
    -        "ANT_OPTS"
    +        "ANT_OPTS",
    +        "AWS_CONFIG_FILE"
         ]
     
         static let blockedOverrideKeys: Set<String> = [
    
  • src/infra/host-env-security-policy.json+3 1 modified
    @@ -12,6 +12,7 @@
         "ENV",
         "GIT_EXTERNAL_DIFF",
         "GIT_EXEC_PATH",
    +    "GIT_TEMPLATE_DIR",
         "SHELL",
         "SHELLOPTS",
         "PS4",
    @@ -28,7 +29,8 @@
         "MAVEN_OPTS",
         "SBT_OPTS",
         "GRADLE_OPTS",
    -    "ANT_OPTS"
    +    "ANT_OPTS",
    +    "AWS_CONFIG_FILE"
       ],
       "blockedOverrideKeys": [
         "HOME",
    
  • src/infra/host-env-security.test.ts+121 0 modified
    @@ -37,13 +37,43 @@ async function runGitLsRemote(gitPath: string, target: string, env: NodeJS.Proce
       });
     }
     
    +async function runGitCommand(
    +  gitPath: string,
    +  args: string[],
    +  options?: {
    +    cwd?: string;
    +    env?: NodeJS.ProcessEnv;
    +  },
    +) {
    +  await new Promise<void>((resolve) => {
    +    const child = spawn(gitPath, args, {
    +      cwd: options?.cwd,
    +      env: options?.env,
    +      stdio: "ignore",
    +    });
    +    child.once("error", () => resolve());
    +    child.once("close", () => resolve());
    +  });
    +}
    +
    +async function runGitClone(
    +  gitPath: string,
    +  source: string,
    +  destination: string,
    +  env: NodeJS.ProcessEnv,
    +) {
    +  await runGitCommand(gitPath, ["clone", source, destination], { env });
    +}
    +
     describe("isDangerousHostEnvVarName", () => {
       it("matches dangerous keys and prefixes case-insensitively", () => {
         expect(isDangerousHostEnvVarName("BASH_ENV")).toBe(true);
         expect(isDangerousHostEnvVarName("bash_env")).toBe(true);
         expect(isDangerousHostEnvVarName("SHELL")).toBe(true);
         expect(isDangerousHostEnvVarName("GIT_EXTERNAL_DIFF")).toBe(true);
         expect(isDangerousHostEnvVarName("git_exec_path")).toBe(true);
    +    expect(isDangerousHostEnvVarName("GIT_TEMPLATE_DIR")).toBe(true);
    +    expect(isDangerousHostEnvVarName("git_template_dir")).toBe(true);
         expect(isDangerousHostEnvVarName("SHELLOPTS")).toBe(true);
         expect(isDangerousHostEnvVarName("ps4")).toBe(true);
         expect(isDangerousHostEnvVarName("DYLD_INSERT_LIBRARIES")).toBe(true);
    @@ -71,6 +101,8 @@ describe("isDangerousHostEnvVarName", () => {
         expect(isDangerousHostEnvVarName("gradle_opts")).toBe(true);
         expect(isDangerousHostEnvVarName("ANT_OPTS")).toBe(true);
         expect(isDangerousHostEnvVarName("ant_opts")).toBe(true);
    +    expect(isDangerousHostEnvVarName("AWS_CONFIG_FILE")).toBe(true);
    +    expect(isDangerousHostEnvVarName("aws_config_file")).toBe(true);
         expect(isDangerousHostEnvVarName("PATH")).toBe(false);
         expect(isDangerousHostEnvVarName("FOO")).toBe(false);
         expect(isDangerousHostEnvVarName("GRADLE_USER_HOME")).toBe(false);
    @@ -84,6 +116,8 @@ describe("sanitizeHostExecEnv", () => {
             PATH: "/usr/bin:/bin",
             BASH_ENV: "/tmp/pwn.sh",
             GIT_EXTERNAL_DIFF: "/tmp/pwn.sh",
    +        GIT_TEMPLATE_DIR: "/tmp/git-template",
    +        AWS_CONFIG_FILE: "/tmp/aws-config",
             LD_PRELOAD: "/tmp/pwn.so",
             OK: "1",
           },
    @@ -126,6 +160,8 @@ describe("sanitizeHostExecEnv", () => {
         expect(env.PATH).toBe("/usr/bin:/bin");
         expect(env.OPENCLAW_CLI).toBe(OPENCLAW_CLI_ENV_VALUE);
         expect(env.BASH_ENV).toBeUndefined();
    +    expect(env.GIT_TEMPLATE_DIR).toBeUndefined();
    +    expect(env.AWS_CONFIG_FILE).toBeUndefined();
         expect(env.GIT_SSH_COMMAND).toBeUndefined();
         expect(env.GIT_EXEC_PATH).toBeUndefined();
         expect(env.EDITOR).toBeUndefined();
    @@ -426,6 +462,91 @@ describe("git env exploit regression", () => {
         }
       });
     
    +  it("blocks inherited GIT_TEMPLATE_DIR so git clone cannot install hook payloads", async () => {
    +    const gitPath = getSystemGitPath();
    +    if (!gitPath) {
    +      return;
    +    }
    +
    +    const repoDir = fs.mkdtempSync(
    +      path.join(os.tmpdir(), `openclaw-git-template-source-${process.pid}-${Date.now()}-`),
    +    );
    +    const cloneDir = path.join(
    +      os.tmpdir(),
    +      `openclaw-git-template-clone-${process.pid}-${Date.now()}`,
    +    );
    +    const safeCloneDir = path.join(
    +      os.tmpdir(),
    +      `openclaw-git-template-safe-clone-${process.pid}-${Date.now()}`,
    +    );
    +    const templateDir = fs.mkdtempSync(
    +      path.join(os.tmpdir(), `openclaw-git-template-dir-${process.pid}-${Date.now()}-`),
    +    );
    +    const hooksDir = path.join(templateDir, "hooks");
    +    const marker = path.join(
    +      os.tmpdir(),
    +      `openclaw-git-template-marker-${process.pid}-${Date.now()}`,
    +    );
    +
    +    try {
    +      fs.mkdirSync(hooksDir, { recursive: true });
    +      clearMarker(marker);
    +      fs.writeFileSync(
    +        path.join(hooksDir, "post-checkout"),
    +        `#!/bin/sh\ntouch ${JSON.stringify(marker)}\n`,
    +        "utf8",
    +      );
    +      fs.chmodSync(path.join(hooksDir, "post-checkout"), 0o755);
    +
    +      await runGitCommand(gitPath, ["init", repoDir]);
    +      await runGitCommand(
    +        gitPath,
    +        [
    +          "-C",
    +          repoDir,
    +          "-c",
    +          "user.name=OpenClaw Test",
    +          "-c",
    +          "user.email=test@example.com",
    +          "commit",
    +          "--allow-empty",
    +          "-m",
    +          "init",
    +        ],
    +        {
    +          env: {
    +            PATH: process.env.PATH ?? "/usr/bin:/bin",
    +          },
    +        },
    +      );
    +
    +      const unsafeEnv = {
    +        PATH: process.env.PATH ?? "/usr/bin:/bin",
    +        GIT_TEMPLATE_DIR: templateDir,
    +        GIT_TERMINAL_PROMPT: "0",
    +      };
    +
    +      await runGitClone(gitPath, repoDir, cloneDir, unsafeEnv);
    +
    +      expect(fs.existsSync(marker)).toBe(true);
    +      clearMarker(marker);
    +
    +      const safeEnv = sanitizeHostExecEnv({
    +        baseEnv: unsafeEnv,
    +      });
    +
    +      await runGitClone(gitPath, repoDir, safeCloneDir, safeEnv);
    +
    +      expect(fs.existsSync(marker)).toBe(false);
    +    } finally {
    +      fs.rmSync(repoDir, { recursive: true, force: true });
    +      fs.rmSync(cloneDir, { recursive: true, force: true });
    +      fs.rmSync(safeCloneDir, { recursive: true, force: true });
    +      fs.rmSync(templateDir, { recursive: true, force: true });
    +      fs.rmSync(marker, { force: true });
    +    }
    +  });
    +
       it("blocks GIT_SSH_COMMAND override so git cannot execute helper payloads", async () => {
         const gitPath = getSystemGitPath();
         if (!gitPath) {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.