fix(dotnet): prevent shell command injection in CLI Agent (fixes #636) - #647
fix(dotnet): prevent shell command injection in CLI Agent (fixes #636)#647kuangmi-bit wants to merge 3 commits into
Conversation
Replace shell-based command execution (/bin/bash -c / cmd.exe /c) with direct process invocation using ProcessStartInfo.ArgumentList. Root cause: ParseCommand only allowlisted the first token, then interpolated the entire string into a shell command line. Shell metacharacters (;, |, &&, $(), backticks) in the argument portion bypassed the allowlist entirely. Changes: - Execute allowlisted commands directly — no shell, no /bin/bash -c - Parse arguments into a List<string>, pass via ArgumentList (argv) - ArgumentList handles platform-specific quoting, metacharacters arrive as literal argv entries — never interpreted by a shell - Remove interpreters (python, node, npm, dotnet) from default allowlist — they accept arbitrary code as arguments - Add security warning: this sample should not be exposed to untrusted clients UseShellExecute = false is not a mitigation here — it only stops .NET from using the OS shell to resolve FileName. The code was explicitly invoking /bin/bash -c (and cmd.exe /c), so a shell parsed the string regardless. Credit to @chopmob-cloud for the detailed root-cause analysis and fix direction. Fixes a2aproject#636
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Verified this against the branch. The sink from #636 is closed, and it is the right shape of fix rather than an escaping patch: there is no shell process left to interpret metacharacters, Three things the change leaves behind. Five allowlist entries only worked because of the shell.
The rest of the list divides cleanly by platform and is unaffected either way. The README now documents the design this PR removes. It still states "Windows: Uses Minor: Worth naming what the change deliberately does not cover, because the added remarks get this right: |
Replace deferred resp.Body.Close() with func() { _ = resp.Body.Close() }()
to satisfy errcheck lint. Both files had the same pattern in HTTP test
helpers that fetch agent cards and JKU public keys.
|
The Error: Root cause: The super-linter runs This PR touches only .NET files ( No action needed from contributor side. |
Address review feedback on a2aproject#647 (chopmob-cloud, 2026-07-22): - Prune shell-only builtins from AllowedCommands (dir, date, time, echo, type): they only resolved through the removed cmd.exe /c wrapper and throw Win32Exception with UseShellExecute=false. type has no Unix binary; time is a shell builtin on both platforms. - Update README: drop cmd.exe//bin/bash execution model, fix example commands and the allowed-commands list to match the actual allowlist. - Update CLIClient/CLIServer prompts, examples and agent descriptions that still advertised dir/date/dotnet --version/node/npm. - Remove now-unused System.Runtime.InteropServices using from CLIAgent.cs.
|
@chopmob-cloud thanks for the thorough review — and apologies for the slow turnaround on it. All three points are addressed in
Beyond the three points, I swept the rest of the demo for stale references to the removed commands: On the deliberate non-coverage you named — |
|
@chopmob-cloud — gentle ping on the re-review. All three points from your 07-22 review are addressed in |
|
@chopmob-cloud — one small ask to get this over the line: your 07-22 review already confirmed the fix is "the right shape" and all three points are addressed in |
Summary
Fixes the shell command injection vulnerability reported in #636.
Root cause:
ParseCommandonly allowlisted the first token, then interpolated the entire string into/bin/bash -c "{command} {arguments}". Shell metacharacters (;,|,&&,$(), backticks) in the argument portion bypassed the allowlist entirely.Fix: Replace shell-based execution with direct process invocation:
ProcessStartInfo, never through/bin/bash -corcmd.exe /cList<string>, pass viaArgumentList(argv).ArgumentListhandles platform-specific quoting; metacharacters arrive as literal argv entriespython,node,npm,dotnet) — they accept arbitrary code as argumentsCredit to @chopmob-cloud for the detailed root-cause analysis and fix direction in #636.