Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions gateway/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ def _ensure_ssl_certs() -> None:
for _cfg_key, _env_var in _terminal_env_map.items():
if _cfg_key in _terminal_cfg:
_val = _terminal_cfg[_cfg_key]
# Don't clobber an already-resolved absolute TERMINAL_CWD.
# cli.py resolves "." to os.getcwd() at import time, but
# this module-level code runs again when gateway/run.py is
# imported as a plugin — it would overwrite the absolute
# path with the raw "." and then line 208-211 falls back
# to Path.home().
if _cfg_key == "cwd" and os.path.isabs(os.environ.get(_env_var, "")):
continue
if isinstance(_val, list):
os.environ[_env_var] = json.dumps(_val)
else:
Expand Down
27 changes: 27 additions & 0 deletions tools/terminal_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,33 @@ def terminal_tool(
"status": "blocked"
}, ensure_ascii=False)

# Validate per-call workdir: fall back to session cwd if invalid.
# Prevents malformed paths (e.g. "/workspace/..???") from being passed
# directly to docker exec -w, which silently fails the command.
# See https://github.com/NousResearch/hermes-agent/issues/4669
if workdir:
_resolved = Path(workdir).resolve()
try:
_resolved.relative_to("/")
except ValueError:
# Path resolves outside root (malformed/relative jank) — ignore
logger.warning(
"Invalid workdir %r resolved to %r, falling back to session cwd %r - Task: %s",
workdir, str(_resolved), getattr(env, "cwd", cwd), effective_task_id,
)
workdir = None
# For non-local backends the path must exist inside the container.
# We can't stat inside the sandbox, so at minimum check it's absolute
# and looks sane. The backend will still fail if the dir doesn't exist
# inside the container, but that's an execution error, not a silent
# config-override bug.
elif not os.path.isabs(workdir):
logger.warning(
"Relative workdir %r is ambiguous across backends, falling back to session cwd - Task: %s",
workdir, effective_task_id,
)
workdir = None

# Prepare command for execution
if background:
# Spawn a tracked background process via the process registry.
Expand Down
Loading