From 3d737c66c5003824874986337c0d42933b15c15f Mon Sep 17 00:00:00 2001 From: John Richmond <5629+jr@users.noreply.github.com> Date: Mon, 29 Sep 2025 15:51:02 -0700 Subject: [PATCH] More restrictions --- webview-ui/src/utils/__tests__/command-validation.spec.ts | 7 +++++++ webview-ui/src/utils/command-validation.ts | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/webview-ui/src/utils/__tests__/command-validation.spec.ts b/webview-ui/src/utils/__tests__/command-validation.spec.ts index 6180e6d28e..acea548e14 100644 --- a/webview-ui/src/utils/__tests__/command-validation.spec.ts +++ b/webview-ui/src/utils/__tests__/command-validation.spec.ts @@ -319,6 +319,11 @@ ls -la || echo "Failed"` // Glob qualifiers with complex commands expect(containsDangerousSubstitution("ls *(e:open -a Calculator:)")).toBe(true) expect(containsDangerousSubstitution("rm *(e:sudo apt install malware:)")).toBe(true) + + // Plus-shorthand qualifier that executes a command + expect(containsDangerousSubstitution("ls *(+whoami)")).toBe(true) + expect(containsDangerousSubstitution("ls *(.+{'whoami'})")).toBe(true) + expect(containsDangerousSubstitution('ls *(+"whoami")')).toBe(true) }) it('detects bash $"..." string interpolation with command substitution', () => { @@ -1045,6 +1050,8 @@ describe("Unified Command Decision Functions", () => { const globExploit = "ls *(e:whoami:)" // Even though 'ls' might be allowed, the dangerous pattern prevents auto-approval expect(getCommandDecision(globExploit, ["ls", "echo"], [])).toBe("ask_user") + // Plus-shorthand form should also prevent auto-approval + expect(getCommandDecision("ls *(+whoami)", ["ls", "echo"], [])).toBe("ask_user") // Zsh extended glob with qualifier list and brace-arg form expect(getCommandDecision("ls *(.e{'whoami'})", ["ls", "echo"], [])).toBe("ask_user") diff --git a/webview-ui/src/utils/command-validation.ts b/webview-ui/src/utils/command-validation.ts index b92aba0d36..9b4f93dad9 100644 --- a/webview-ui/src/utils/command-validation.ts +++ b/webview-ui/src/utils/command-validation.ts @@ -115,6 +115,12 @@ export function containsDangerousSubstitution(source: string): boolean { // Any appearance of an "e" qualifier with an argument inside a glob qualifier list is dangerous. const zshGlobQualifier = /\([^)]*e\s*(?::[^:]*:|\{[^}]*\}|'[^']*'|"[^"]*")[^)]*\)/.test(source) + // Check for zsh glob qualifier shorthand that executes code using +command during glob expansion + // Examples: *(+whoami), *(.+{'whoami'}), *(+"whoami") + // Treat + followed by a non-digit token inside a qualifier list as executable (exclude numeric-only like (+1)) + const zshGlobQualifierPlusShorthand = + /[?*@+!]\([^)]*\+\s*(?:\{[^}]*\}|'[^']*'|"[^"]*"|[a-zA-Z_][^)\s]*)[^)]*\)/.test(source) + // Check for $"..." string interpolation with command substitution // $"..." is a bash feature for translated strings that allows command substitution inside // e.g., echo $"test$(whoami)" or echo $"test`pwd`" @@ -128,6 +134,7 @@ export function containsDangerousSubstitution(source: string): boolean { hereStringWithSubstitution || zshProcessSubstitution || zshGlobQualifier || + zshGlobQualifierPlusShorthand || bashTranslatedStringWithSubstitution ) }