mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-23 10:42:00 +00:00
fix(security): quote HERMES_TIMEZONE in remote code execution to prevent shell injection
This commit is contained in:
parent
bef1d3e4ff
commit
84fcbbf6a9
2 changed files with 42 additions and 1 deletions
|
|
@ -174,6 +174,47 @@ class TestExecuteCodeRemoteTempDir(unittest.TestCase):
|
|||
self.assertIn("rm -rf /data/data/com.termux/files/usr/tmp/hermes_exec_", cleanup_cmd)
|
||||
self.assertNotIn("mkdir -p /tmp/hermes_exec_", mkdir_cmd)
|
||||
|
||||
def test_timezone_shell_quoted_in_remote_execution(self):
|
||||
"""HERMES_TIMEZONE must be shell-quoted in remote env_prefix to prevent injection."""
|
||||
class FakeEnv:
|
||||
def __init__(self):
|
||||
self.commands = []
|
||||
|
||||
def get_temp_dir(self):
|
||||
return "/tmp"
|
||||
|
||||
def execute(self, command, cwd=None, timeout=None):
|
||||
self.commands.append((command, cwd, timeout))
|
||||
if "command -v python3" in command:
|
||||
return {"output": "OK\n"}
|
||||
if "python3 script.py" in command:
|
||||
return {"output": "hello\n", "returncode": 0}
|
||||
return {"output": ""}
|
||||
|
||||
env = FakeEnv()
|
||||
fake_thread = MagicMock()
|
||||
|
||||
malicious_tz = "US/Eastern; echo PWNED"
|
||||
|
||||
with patch("tools.code_execution_tool._load_config",
|
||||
return_value={"timeout": 30, "max_tool_calls": 5}), \
|
||||
patch("tools.code_execution_tool._get_or_create_env",
|
||||
return_value=(env, "ssh")), \
|
||||
patch("tools.code_execution_tool._ship_file_to_remote"), \
|
||||
patch("tools.code_execution_tool.threading.Thread",
|
||||
return_value=fake_thread), \
|
||||
patch.dict(os.environ, {"HERMES_TIMEZONE": malicious_tz}):
|
||||
result = json.loads(_execute_remote("print('hello')", "task-1", ["terminal"]))
|
||||
|
||||
self.assertEqual(result["status"], "success")
|
||||
run_cmd = next(cmd for cmd, _, _ in env.commands if "python3 script.py" in cmd)
|
||||
# The TZ value must be shell-quoted — it should NOT contain unescaped semicolons
|
||||
self.assertNotIn("TZ=US/Eastern; echo PWNED", run_cmd,
|
||||
"TZ value with shell metacharacters must not appear unquoted")
|
||||
# shlex.quote wraps values containing special characters in single quotes
|
||||
self.assertIn("TZ='US/Eastern; echo PWNED'", run_cmd,
|
||||
"TZ value must be wrapped in single quotes by shlex.quote()")
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform == "win32", "UDS not available on Windows")
|
||||
class TestExecuteCode(unittest.TestCase):
|
||||
|
|
|
|||
|
|
@ -961,7 +961,7 @@ def _execute_remote(
|
|||
)
|
||||
tz = os.getenv("HERMES_TIMEZONE", "").strip()
|
||||
if tz:
|
||||
env_prefix += f" TZ={tz}"
|
||||
env_prefix += f" TZ={shlex.quote(tz)}"
|
||||
|
||||
# Execute the script on the remote backend
|
||||
logger.info("Executing code on %s backend (task %s)...",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue