mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-30 11:52:04 +00:00
fix(daytona): quote single-upload mkdir parent path (#54440)
* fix(daytona): quote single-upload mkdir parent path
The single-file _daytona_upload() path shelled out 'mkdir -p {parent}'
with the remote parent interpolated unquoted, so shell metacharacters in
the path could break the command or inject arbitrary commands into the
sandbox. The bulk-upload, bulk-download, and delete paths were already
hardened with shlex-quoting helpers; this single-upload path was missed.
Route it through the existing quoted_mkdir_command() helper and add a
regression test covering a path with shell metacharacters.
Reported by @Gutslabs (#3960); the original branch predated the
file_sync refactor, so the fix is re-applied to the current code path.
* docs(infographic): daytona quote-sync fix
This commit is contained in:
parent
c648ecdca5
commit
e5d22ab80d
3 changed files with 28 additions and 1 deletions
BIN
infographic/daytona-quote-sync/infographic.png
Normal file
BIN
infographic/daytona-quote-sync/infographic.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
|
|
@ -413,3 +413,30 @@ class TestEnsureSandboxReady:
|
|||
env._sandbox.state = "started"
|
||||
env._ensure_sandbox_ready()
|
||||
env._sandbox.start.assert_not_called()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sync safety: shell-metacharacter quoting
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestSyncSafety:
|
||||
def test_single_upload_quotes_parent_path(self, make_env, tmp_path):
|
||||
"""A remote path with shell metacharacters must be quoted, not injected."""
|
||||
env = make_env()
|
||||
env._sandbox.process.exec.reset_mock()
|
||||
|
||||
host_file = tmp_path / "token.txt"
|
||||
host_file.write_text("secret", encoding="utf-8")
|
||||
remote_path = "/root/.hermes/skills/evil; touch /tmp/daytona-owned/file.txt"
|
||||
|
||||
env._daytona_upload(str(host_file), remote_path)
|
||||
|
||||
mkdir_cmd = env._sandbox.process.exec.call_args_list[0][0][0]
|
||||
# The whole parent dir is a single quoted argument — the ';' cannot
|
||||
# break out into a second command.
|
||||
assert mkdir_cmd == (
|
||||
"mkdir -p '/root/.hermes/skills/evil; touch /tmp/daytona-owned'"
|
||||
)
|
||||
assert "; touch" not in mkdir_cmd.replace(
|
||||
"'/root/.hermes/skills/evil; touch /tmp/daytona-owned'", ""
|
||||
)
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ class DaytonaEnvironment(BaseEnvironment):
|
|||
def _daytona_upload(self, host_path: str, remote_path: str) -> None:
|
||||
"""Upload a single file via Daytona SDK."""
|
||||
parent = str(Path(remote_path).parent)
|
||||
self._sandbox.process.exec(f"mkdir -p {parent}")
|
||||
self._sandbox.process.exec(quoted_mkdir_command([parent]))
|
||||
self._sandbox.fs.upload_file(host_path, remote_path)
|
||||
|
||||
def _daytona_bulk_upload(self, files: list[tuple[str, str]]) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue