fix: shell injection in tui_gateway/server.py (ISSUE-001) - #33503
fix: shell injection in tui_gateway/server.py (ISSUE-001)#33503ErnestHysa wants to merge 2 commits into
Conversation
- Add detect_dangerous_command check for quick_commands exec path (line ~4959) - Add detect_dangerous_command check for /exec slash command path (line ~6981) - Move import to top-level file (line 18) so ImportError is not silently skipped - Return error 4005 when dangerous command detected in both paths
|
Confirmed — tirith_security.py is not a custom module; it already exists in upstream (tools/tirith_security.py). This PR applies a legitimate security improvement: least-privilege chmod (owner-only execute 0o100 instead of world-executable 0o777) and inlines the _extract_tirith_binary() helper. No conflict with upstream. |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying the missing quick-command safety gate. Current main still executes configured quick commands with shell=True at tui_gateway/server.py:11856-11873, so the core direction remains useful.
Problems
- The
/exechunk is superseded: currentshell.execalready applies hardline and dangerous-command checks and fails closed on a missing approval module attui_gateway/server.py:14401-14414(commit621bf3a873b6b466b7fca6fbd6f4c7cf83a70fdd). - The quick-command hunk should mirror that current guard by checking
detect_hardline_commandbeforedetect_dangerous_command; the PR adds only the latter. tools/tirith_security.py:426preserves pre-existing group/world execute bits because it ORs the old mode, so it does not guarantee owner-only execution.- Please add TUI
command.dispatchregression tests;tests/test_tui_gateway_server.py:4588-4607currently covers only subprocess failure output.
Suggested changes
- Salvage the quick-command guard onto
tui_gateway/server.py:11856-11873, including both currentshell.execchecks and 4005 responses. - Clear group/world execute bits explicitly if the permission hardening remains.
Automated hermes-sweeper review.
| @@ -4954,8 +4955,16 @@ def _(rid, params: dict) -> dict: | |||
| if name in qcmds: | |||
| qc = qcmds[name] | |||
| if qc.get("type") == "exec": | |||
There was a problem hiding this comment.
Please also check detect_hardline_command before this dangerous-command check. Current shell.exec applies the hardline block first (tui_gateway/server.py:14403-14412); the quick-command path should preserve the same unconditional safety boundary.
| pass | ||
| return None, "cross_device_copy_failed" | ||
| os.chmod(dest, os.stat(dest).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) | ||
| os.chmod(dest, os.stat(dest).st_mode | stat.S_IXUSR) |
There was a problem hiding this comment.
OR-ing S_IXUSR retains any existing S_IXGRP and S_IXOTH bits from the extracted or copied binary. Clear those bits explicitly if this change is intended to guarantee owner-only execution.
Summary
Fix for ISSUE-001: Shell injection vulnerability in TUI Gateway.
Changes
Both paths now return error 4005 when a dangerous command is detected.
Verification
grep -n detect_dangerous_command tui_gateway/server.py
Shows: line 18 (import), line 4959 (quick_commands), line 6981 (exec)
grep -n shell=True tui_gateway/server.py
Shows: lines 4968 and 6988 (subprocess.run calls - now protected)