mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-30 20:17:47 +00:00
fix(security): validate snapshot_id and file paths in restore_quick_snapshot to prevent path traversal
This commit is contained in:
@@ -900,8 +900,22 @@ def restore_quick_snapshot(
|
||||
"""
|
||||
home = hermes_home or get_hermes_home()
|
||||
root = _quick_snapshot_root(home)
|
||||
|
||||
# Security: reject snapshot_id values that contain path separators or
|
||||
# traversal sequences so that `root / snapshot_id` stays inside root.
|
||||
if not snapshot_id or "/" in snapshot_id or "\\" in snapshot_id or snapshot_id in (".", ".."):
|
||||
logger.error("Invalid snapshot_id: %s", snapshot_id)
|
||||
return False
|
||||
|
||||
snap_dir = root / snapshot_id
|
||||
|
||||
# Confirm the resolved path is still inside root (handles symlinks etc.)
|
||||
try:
|
||||
snap_dir.resolve().relative_to(root.resolve())
|
||||
except ValueError:
|
||||
logger.error("Snapshot path traversal blocked for id: %s", snapshot_id)
|
||||
return False
|
||||
|
||||
if not snap_dir.is_dir():
|
||||
return False
|
||||
|
||||
@@ -914,11 +928,24 @@ def restore_quick_snapshot(
|
||||
|
||||
restored = 0
|
||||
for rel in meta.get("files", {}):
|
||||
# Security: reject absolute paths and traversals in manifest entries
|
||||
src = snap_dir / rel
|
||||
if not src.exists():
|
||||
try:
|
||||
src.resolve().relative_to(snap_dir.resolve())
|
||||
except ValueError:
|
||||
logger.error("Manifest path traversal blocked: %s", rel)
|
||||
continue
|
||||
|
||||
dst = home / rel
|
||||
try:
|
||||
dst.resolve().relative_to(home.resolve())
|
||||
except ValueError:
|
||||
logger.error("Manifest path traversal blocked: %s", rel)
|
||||
continue
|
||||
|
||||
if not src.exists():
|
||||
continue
|
||||
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user