From 9bcd31fcd2bd7fc015dd41c28e26f71bd45436b2 Mon Sep 17 00:00:00 2001 From: roboomp Date: Mon, 3 Aug 2026 21:08:52 +0000 Subject: [PATCH] fix(coding-agent): blocked reinterpreted quoted shell payloads - Kept quoted shell controls prompt-gated when code-evaluation options can reinterpret the argument. - Covered the reported git inline shell-alias bypass while retaining Cargo regex approval. Fixes #7552 --- packages/coding-agent/src/tools/bash.ts | 12 ++++++++++-- packages/coding-agent/test/tools/approval.test.ts | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/coding-agent/src/tools/bash.ts b/packages/coding-agent/src/tools/bash.ts index f051fde50..1bf747195 100644 --- a/packages/coding-agent/src/tools/bash.ts +++ b/packages/coding-agent/src/tools/bash.ts @@ -71,13 +71,19 @@ const BASH_APPROVAL_SHELL_CONTROL_CHARS: Record = { "(": true, ")": true, }; +const BASH_APPROVAL_REINTERPRETED_ARGUMENT_RE = /(?:^|[ \t])(?:-[^-]*[ce]|--(?:command|eval))(?:[= \t]|$)/u; function hasBashApprovalShellControl(command: string): boolean { let quote: "'" | '"' | undefined; + let hasQuotedShellControl = false; for (let i = 0; i < command.length; i++) { const ch = command[i]; if (quote === "'") { - if (ch === "'") quote = undefined; + if (ch === "'") { + quote = undefined; + } else if (Object.hasOwn(BASH_APPROVAL_SHELL_CONTROL_CHARS, ch)) { + hasQuotedShellControl = true; + } continue; } if (ch === "\\") { @@ -100,7 +106,9 @@ function hasBashApprovalShellControl(command: string): boolean { } if (Object.hasOwn(BASH_APPROVAL_SHELL_CONTROL_CHARS, ch)) return true; } - return false; + // Options such as `git -c alias.x='!...'` and `sh -c '...'` reinterpret + // otherwise literal single-quoted arguments as executable code. + return hasQuotedShellControl && BASH_APPROVAL_REINTERPRETED_ARGUMENT_RE.test(command); } const BASH_PATTERN_APPROVAL_VALUES = new Set(["allow", "deny", "prompt"]); diff --git a/packages/coding-agent/test/tools/approval.test.ts b/packages/coding-agent/test/tools/approval.test.ts index acfbfaa0c..1edd69fac 100644 --- a/packages/coding-agent/test/tools/approval.test.ts +++ b/packages/coding-agent/test/tools/approval.test.ts @@ -329,6 +329,7 @@ describe("tool-owned dynamic approval declarations", () => { "git $(rm file.txt)", "git `rm file.txt` status", "git status > /etc/passwd", + "git -c alias.x='!touch /tmp/pwn; printf ok' x", "git status < seed", // Different binary resolution than the pattern names. "FOO=1 git status",