What version of tRPC-Agent-Python are you using?
Current main at commit 1153e7f8455f867634ac4babf0be5717152711bf.
What operating system and Python version are you using?
- Windows 11
- CPython 3.14.6
The affected parser uses shlex, and the underlying logic error is platform-independent.
What did you do?
I inspected BashTool._is_command_safe() and called that predicate directly with a custom whitelist. This was a static check only: none of the sample strings were passed to a shell or executed.
tool = BashTool(whitelist_commands=["echo"])
tool._is_command_safe("blocked_cmd", tool.cwd)
tool._is_command_safe("echo ok; blocked_cmd", tool.cwd)
tool._is_command_safe("echo ok && blocked_cmd", tool.cwd)
tool._is_command_safe("echo ok || blocked_cmd", tool.cwd)
tool._is_command_safe("echo ok\nblocked_cmd", tool.cwd)
tool._is_command_safe("echo ok | blocked_cmd", tool.cwd)
All six calls currently return True.
What did you expect to see?
A command should be considered safe only when every executable command segment is present in the configured whitelist.
The standalone non-whitelisted command and every compound command containing blocked_cmd should return False. A pipeline containing only whitelisted commands should continue to return True.
What did you see instead?
The whitelist is skipped for standalone commands and for the final command in a pipeline. Shell separators other than a single pipe are not treated as command boundaries.
The parser appends current_command[0] to base_commands only when it encounters |, but it never appends the final current_command after the loop. Consequently:
- a standalone command leaves
base_commands empty;
- the final pipeline command is not checked;
;, &&, ||, background execution, and newlines are not parsed as command boundaries;
- command substitution also needs an explicit fail-closed policy.
Because _run_async_impl() uses create_subprocess_shell() after this check, the behavior can bypass the documented custom whitelist and the default outside-workdir command restriction when the optional Tool Safety Guard is disabled.
Suggested direction
- Always validate the final parsed command segment.
- Recognize the shell control operators supported by the tool, including pipelines and compound command separators.
- Reject or explicitly inspect command/process substitution rather than treating it as a normal argument.
- Fail closed when parsing cannot prove that every executable command is allowlisted.
- Add predicate-only regression tests; the test strings do not need to be executed.
Useful cases include:
- one allowed standalone command;
- one denied standalone command;
- an all-allowed pipeline;
- a pipeline whose final command is denied;
;, &&, ||, newline, and background separators;
- command substitution.
I would like to work on a focused fix and tests if this behavior and scope are accepted.
What version of tRPC-Agent-Python are you using?
Current
mainat commit1153e7f8455f867634ac4babf0be5717152711bf.What operating system and Python version are you using?
The affected parser uses
shlex, and the underlying logic error is platform-independent.What did you do?
I inspected
BashTool._is_command_safe()and called that predicate directly with a custom whitelist. This was a static check only: none of the sample strings were passed to a shell or executed.All six calls currently return
True.What did you expect to see?
A command should be considered safe only when every executable command segment is present in the configured whitelist.
The standalone non-whitelisted command and every compound command containing
blocked_cmdshould returnFalse. A pipeline containing only whitelisted commands should continue to returnTrue.What did you see instead?
The whitelist is skipped for standalone commands and for the final command in a pipeline. Shell separators other than a single pipe are not treated as command boundaries.
The parser appends
current_command[0]tobase_commandsonly when it encounters|, but it never appends the finalcurrent_commandafter the loop. Consequently:base_commandsempty;;,&&,||, background execution, and newlines are not parsed as command boundaries;Because
_run_async_impl()usescreate_subprocess_shell()after this check, the behavior can bypass the documented custom whitelist and the default outside-workdir command restriction when the optional Tool Safety Guard is disabled.Suggested direction
Useful cases include:
;,&&,||, newline, and background separators;I would like to work on a focused fix and tests if this behavior and scope are accepted.