From 5839822aa1d17b162720a34c679071fc08ed0e50 Mon Sep 17 00:00:00 2001 From: Huang-404-Q <129407632+Huang-404-Q@users.noreply.github.com> Date: Fri, 23 Oct 2026 14:54:21 +0800 Subject: [PATCH] fix(agents): validate the agent name in FileAgentStore.get_soul (#7265) get_soul was the only read/write method that skipped validate_agent_name, so a name like "../../other-user/agents/planner" reached resolve_agent_dir and read another user's SOUL.md. Validate it like the other methods do. The regression test asserts ValueError for a traversal name; it reads the other user's soul on main. Co-authored-by: Willem Jiang --- .../packages/harness/deerflow/persistence/agents/file.py | 3 +++ backend/tests/test_agent_storage_backend.py | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/backend/packages/harness/deerflow/persistence/agents/file.py b/backend/packages/harness/deerflow/persistence/agents/file.py index 123c37036d..146c1b4666 100644 --- a/backend/packages/harness/deerflow/persistence/agents/file.py +++ b/backend/packages/harness/deerflow/persistence/agents/file.py @@ -64,6 +64,9 @@ class FileAgentStore(AgentStore): return paths.user_agent_dir(effective_user, name).exists() or paths.agent_dir(name).exists() def get_soul(self, name: str, *, user_id: str | None = None) -> str | None: + # Every other read/write method validates the name; without this, a + # ".." segment reaches resolve_agent_dir and escapes the user's tree. + name = validate_agent_name(name) agent_dir = resolve_agent_dir(name, user_id=user_id) soul_path = agent_dir / SOUL_FILENAME # resolve_agent_dir requires config.yaml; SOUL.md loading does not, so diff --git a/backend/tests/test_agent_storage_backend.py b/backend/tests/test_agent_storage_backend.py index 14db9bcb13..9f46e36945 100644 --- a/backend/tests/test_agent_storage_backend.py +++ b/backend/tests/test_agent_storage_backend.py @@ -426,3 +426,10 @@ def test_get_agent_store_does_not_fallback_when_extensions_config_is_missing(tmp finally: reset_app_config() reset_extensions_config() + + +def test_file_get_soul_rejects_path_traversal(file_home): + store = FileAgentStore() + + with pytest.raises(ValueError, match="Invalid agent name"): + store.get_soul("../../u2/agents/planner", user_id="u1")