fix(security): restrict local workspace writes to configured root
This commit is contained in:
@@ -31,6 +31,13 @@ class Settings(BaseSettings):
|
||||
cors_origins: str = ""
|
||||
base_url: str = ""
|
||||
|
||||
# Optional: local directory where the backend is allowed to write "preserved" agent
|
||||
# workspace files (e.g. USER.md/SELF.md/MEMORY.md). If empty, local writes are disabled
|
||||
# and provisioning relies on the gateway API.
|
||||
#
|
||||
# Security note: do NOT point this at arbitrary system paths in production.
|
||||
local_agent_workspace_root: str = ""
|
||||
|
||||
# Database lifecycle
|
||||
db_auto_migrate: bool = False
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
@@ -181,9 +182,22 @@ def _ensure_workspace_file(
|
||||
) -> None:
|
||||
if not workspace_path or not name:
|
||||
return
|
||||
# `gateway.workspace_root` is sometimes configured as `~/.openclaw`.
|
||||
# Expand user here to avoid creating a literal `./~` directory under the backend cwd.
|
||||
root = Path(workspace_path).expanduser()
|
||||
# Only write to a dedicated, explicitly-configured local directory.
|
||||
# Using `gateway.workspace_root` directly here is unsafe (and CodeQL correctly flags it)
|
||||
# because it is a DB-backed config value.
|
||||
base_root = (settings.local_agent_workspace_root or "").strip()
|
||||
if not base_root:
|
||||
return
|
||||
base = Path(base_root).expanduser()
|
||||
|
||||
# Derive a stable, safe directory name from the (potentially untrusted) workspace path.
|
||||
# This prevents path traversal and avoids writing to arbitrary locations.
|
||||
digest = hashlib.sha256(workspace_path.encode("utf-8")).hexdigest()[:16]
|
||||
root = base / f"gateway-workspace-{digest}"
|
||||
|
||||
# Ensure `name` is a plain filename (no path separators).
|
||||
if Path(name).name != name:
|
||||
return
|
||||
path = root / name
|
||||
if not overwrite and path.exists():
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user