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
This commit is contained in:
roboomp
2026-08-03 21:08:52 +00:00
parent 54b2e38564
commit 9bcd31fcd2
2 changed files with 11 additions and 2 deletions
+10 -2
View File
@@ -71,13 +71,19 @@ const BASH_APPROVAL_SHELL_CONTROL_CHARS: Record<string, true> = {
"(": 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"]);
@@ -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",