VYPR
Low severityNVD Advisory· Published Mar 23, 2026· Updated Mar 25, 2026

OpenClaw < 2026.3.7 - Shell Approval Gating Bypass via Dispatch Wrapper Depth Mismatch

CVE-2026-27183

Description

OpenClaw versions prior to 2026.3.7 contain a shell approval gating bypass vulnerability in system.run dispatch-wrapper handling that allows attackers to skip shell wrapper approval requirements. The approval classifier and execution planner apply different depth-boundary rules, permitting exactly four transparent dispatch wrappers like repeated env invocations before /bin/sh -c to bypass security=allowlist approval gating by misaligning classification with execution planning.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
openclawnpm
< 2026.3.72026.3.7

Affected products

1

Patches

1
2fc95a7cfc1e

fix(exec): close dispatch-wrapper boundary drift

https://github.com/openclaw/openclawPeter SteinbergerMar 7, 2026via ghsa
4 files changed · +58 2
  • CHANGELOG.md+1 0 modified
    @@ -305,6 +305,7 @@ Docs: https://docs.openclaw.ai
     - Media/mime unknown-kind handling: return `undefined` (not `"unknown"`) for missing/unrecognized MIME kinds and use document-size fallback caps for unknown remote media, preventing phantom `<media:unknown>` Signal events from being treated as real messages. (#39199) Thanks @nicolasgrasset.
     - Nodes/system.run allow-always persistence: honor shell comment semantics during allowlist analysis so `#`-tailed payloads that never execute are not persisted as trusted follow-up commands. Thanks @tdjackey for reporting.
     - Signal/inbound attachment fan-in: forward all successfully fetched inbound attachments through `MediaPaths`/`MediaUrls`/`MediaTypes` (instead of only the first), and improve multi-attachment placeholder summaries in mention-gated pending history. (#39212) Thanks @joeykrug.
    +- Nodes/system.run dispatch-wrapper boundary: keep shell-wrapper approval classification active at the depth boundary so `env` wrapper stacks cannot reach `/bin/sh -c` execution without the expected approval gate. Thanks @tdjackey for reporting.
     
     ## 2026.3.2
     
    
  • src/infra/exec-wrapper-resolution.ts+6 2 modified
    @@ -509,7 +509,9 @@ function hasEnvManipulationBeforeShellWrapperInternal(
       depth: number,
       envManipulationSeen: boolean,
     ): boolean {
    -  if (depth >= MAX_DISPATCH_WRAPPER_DEPTH) {
    +  // The wrapper found exactly at the configured dispatch depth boundary still needs
    +  // to participate in approval classification; only paths beyond that boundary fail closed.
    +  if (depth > MAX_DISPATCH_WRAPPER_DEPTH) {
         return false;
       }
     
    @@ -607,7 +609,9 @@ function extractShellWrapperCommandInternal(
       rawCommand: string | null,
       depth: number,
     ): ShellWrapperCommand {
    -  if (depth >= MAX_DISPATCH_WRAPPER_DEPTH) {
    +  // The shell wrapper reached at the boundary depth is still semantically relevant.
    +  // Only deeper wrapper stacks should be dropped as overflow.
    +  if (depth > MAX_DISPATCH_WRAPPER_DEPTH) {
         return { isWrapper: false, command: null };
       }
     
    
  • src/infra/system-run-command.test.ts+11 0 modified
    @@ -54,6 +54,17 @@ describe("system run command helpers", () => {
             "echo hi",
           ]),
         ).toBe("echo hi");
    +    expect(
    +      extractShellCommandFromArgv([
    +        "/usr/bin/env",
    +        "/usr/bin/env",
    +        "/usr/bin/env",
    +        "/usr/bin/env",
    +        "/bin/sh",
    +        "-c",
    +        "echo hi",
    +      ]),
    +    ).toBe("echo hi");
       });
     
       test("extractShellCommandFromArgv supports fish and pwsh wrappers", () => {
    
  • src/node-host/invoke-system-run.test.ts+40 0 modified
    @@ -858,6 +858,46 @@ describe("handleSystemRunInvoke mac app exec host routing", () => {
         expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
       });
     
    +  it("denies env-wrapped shell payloads at the dispatch depth boundary", async () => {
    +    if (process.platform === "win32") {
    +      return;
    +    }
    +    const { runCommand, sendInvokeResult, sendNodeEvent } = createInvokeSpies({
    +      runCommand: vi.fn(async () => {
    +        throw new Error("runCommand should not be called for depth-boundary shell wrappers");
    +      }),
    +    });
    +
    +    await withTempApprovalsHome({
    +      approvals: createAllowlistOnMissApprovals({
    +        agents: {
    +          main: {
    +            allowlist: [{ pattern: "/usr/bin/env" }],
    +          },
    +        },
    +      }),
    +      run: async ({ tempHome }) => {
    +        const marker = path.join(tempHome, "depth4-pwned.txt");
    +        await runSystemInvoke({
    +          preferMacAppExecHost: false,
    +          command: buildNestedEnvShellCommand({
    +            depth: 4,
    +            payload: `echo PWNED > ${marker}`,
    +          }),
    +          security: "allowlist",
    +          ask: "on-miss",
    +          runCommand,
    +          sendInvokeResult,
    +          sendNodeEvent,
    +        });
    +        expect(fs.existsSync(marker)).toBe(false);
    +      },
    +    });
    +
    +    expect(runCommand).not.toHaveBeenCalled();
    +    expectApprovalRequiredDenied({ sendNodeEvent, sendInvokeResult });
    +  });
    +
       it("denies nested env shell payloads when wrapper depth is exceeded", async () => {
         if (process.platform === "win32") {
           return;
    

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

6

News mentions

0

No linked articles in our index yet.