diff --git a/backend/packages/harness/deerflow/agents/middlewares/input_sanitization_middleware.py b/backend/packages/harness/deerflow/agents/middlewares/input_sanitization_middleware.py index 5c19cdac5..ca824a77f 100644 --- a/backend/packages/harness/deerflow/agents/middlewares/input_sanitization_middleware.py +++ b/backend/packages/harness/deerflow/agents/middlewares/input_sanitization_middleware.py @@ -90,6 +90,10 @@ _BLOCKED_TAG_NAMES: frozenset[str] = frozenset( "guidelines", "output_format", "working_directory", + # Subagent system-prompt block (general_purpose.py): declares the task + # tool off-limits. Forging this in untrusted input could trick the + # model into believing it has (or lacks) tool restrictions it does not. + "tool_restrictions", # Common prompt-injection tag patterns "system", "instruction", diff --git a/backend/packages/harness/deerflow/subagents/builtins/general_purpose.py b/backend/packages/harness/deerflow/subagents/builtins/general_purpose.py index c5291d1b5..0a9f8e3c2 100644 --- a/backend/packages/harness/deerflow/subagents/builtins/general_purpose.py +++ b/backend/packages/harness/deerflow/subagents/builtins/general_purpose.py @@ -24,6 +24,14 @@ Do NOT use for simple, single-step operations.""", - Do NOT ask for clarification - work with the information provided + +You are a subagent - the `task` tool is NOT available to you. +You must NEVER attempt to call `task` or dispatch further subagents. +Complete your delegated work directly using `bash`, `web_search`, `web_fetch`, +`read_file`, and other available tools. +If parallelism is needed, use bash background processes or handle steps sequentially. + + When revising an existing file, prefer `str_replace` over `write_file` — it sends only the diff and avoids re-emitting the whole file (mirrors diff --git a/backend/tests/test_subagent_prompt_security.py b/backend/tests/test_subagent_prompt_security.py index 015206877..9d558211e 100644 --- a/backend/tests/test_subagent_prompt_security.py +++ b/backend/tests/test_subagent_prompt_security.py @@ -55,3 +55,17 @@ def test_general_purpose_subagent_prompt_mentions_workspace_relative_paths() -> assert "Treat `/mnt/user-data/workspace` as the default working directory for coding and file IO" in GENERAL_PURPOSE_CONFIG.system_prompt assert "`hello.txt`, `../uploads/input.csv`, and `../outputs/result.md`" in GENERAL_PURPOSE_CONFIG.system_prompt + + +def test_general_purpose_subagent_prompt_prohibits_task_tool() -> None: + """The system prompt must explicitly tell the LLM that `task` is unavailable. + + Without this, subagents may attempt to call `task` after seeing the parent + agent use it, triggering a LangGraph tool validation error (#4159). + """ + from deerflow.subagents.builtins.general_purpose import GENERAL_PURPOSE_CONFIG + + prompt = GENERAL_PURPOSE_CONFIG.system_prompt + assert "task" in prompt.lower() + assert "NOT available" in prompt or "must NEVER" in prompt + assert "disallowed_tools" not in prompt # don't leak internal implementation details