diff --git a/workspace/builtin_tools/a2a_tools.py b/workspace/builtin_tools/a2a_tools.py index a7edfcdd..2ededa76 100644 --- a/workspace/builtin_tools/a2a_tools.py +++ b/workspace/builtin_tools/a2a_tools.py @@ -12,8 +12,7 @@ import httpx # OFFSEC-003: peer-controlled text MUST be wrapped with sanitize_a2a_result # before being returned to the LLM. This module's delegate_task() is one of # the trust-boundary entry points where peer output crosses into our agent's -# context — same surface as a2a_tools_delegation.py:325 (fixed via #492). -# Issue #537. +# context. Issue #537 / mc#787. from _sanitize_a2a import sanitize_a2a_result PLATFORM_URL = os.environ.get("PLATFORM_URL", "http://host.docker.internal:8080") @@ -76,6 +75,8 @@ async def delegate_task(workspace_id: str, task: str) -> str: result = data["result"] parts = result.get("parts", []) if isinstance(result, dict) else [] if parts and isinstance(parts[0], dict): + # OFFSEC-003: wrap peer-controlled text before returning + # to LLM context. Issue #537 / mc#787. return sanitize_a2a_result(parts[0].get("text", "(no text)")) # Empty parts list (e.g. {"parts": []}) should return str(result), # not "(no text)" — preserves pre-fix behavior (#279 regression fix). @@ -93,8 +94,9 @@ async def delegate_task(workspace_id: str, task: str) -> str: msg = err else: msg = str(err) - return f"Error: {msg}" - return str(data) + # OFFSEC-003: peer-controlled error message; wrap before return. + return sanitize_a2a_result(f"Error: {msg}") + return sanitize_a2a_result(str(data)) except Exception as e: return f"Error sending A2A message: {e}"