fix(security): catch all-wildcard allow patterns in exec approval policy

ValidateExecApprovalRules rejected single '*' but missed patterns like
'**', '***', '?', '? *', '* ?' that also match any command string.

An agent that can call system.execApprovals.set could bypass the
broad-allow restriction by submitting '**' as an allow pattern:
  {"rules": [{"pattern": "**", "action": "allow"}], "baseHash": "..."}

The glob-to-regex translation turns '**' into '^.*.*$', which matches
every command, exactly like '*' does.

Fix: strip all wildcard chars ('*', '?') and whitespace from the
normalised pattern before checking. If nothing remains the pattern is
an all-wildcard glob and is rejected as broad.  The explicit shell-
prefix checks (powershell *, pwsh *, cmd *, cmd.exe *) are preserved
for patterns that contain meaningful content but are still too broad.

Tests: add **,  ***, ?, '? *', '* ?' to ExecApprovalsSet_RejectsUnsafeAllowRules.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
github-actions[bot] 2026-04-30 13:12:32 +00:00 committed by GitHub
parent 29510a16eb
commit ca1fe82301
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 16 additions and 1 deletions

View File

@ -630,7 +630,17 @@ public class SystemCapability : NodeCapabilityBase
return "Empty allow rule patterns are not permitted.";
var normalized = pattern.ToLowerInvariant();
if (normalized is "*" or "* *" or "powershell *" or "pwsh *" or "cmd *" or "cmd.exe *")
// Catch all-wildcard patterns (e.g. *, **, ?*, * ?) that match any command.
// Strip every wildcard character and whitespace; if nothing remains the pattern
// is effectively "match everything" and must be blocked regardless of spelling.
var nonWildcardContent = normalized.Replace("*", "").Replace("?", "").Trim();
if (string.IsNullOrEmpty(nonWildcardContent))
return $"Broad allow rule is not permitted: {pattern}";
// Catch shell-prefixed blanket patterns that match all commands in a given shell
// (e.g. "powershell *" allows every PowerShell command).
if (normalized is "powershell *" or "pwsh *" or "cmd *" or "cmd.exe *")
return $"Broad allow rule is not permitted: {pattern}";
foreach (var dangerous in DangerousAllowPatternFragments)

View File

@ -553,6 +553,11 @@ public class SystemCapabilityTests
[Theory]
[InlineData("*")]
[InlineData("**")]
[InlineData("***")]
[InlineData("?")]
[InlineData("? *")]
[InlineData("* ?")]
[InlineData("cmd *")]
[InlineData("Remove-Item *")]
[InlineData("Invoke-WebRequest *")]