fix(builtin/a2a): restore OFFSEC-003 sanitize_a2a_result wrapping (mc#787)
All checks were successful
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 15s
sop-tier-check / tier-check (pull_request) Successful in 19s
audit-force-merge / audit (pull_request) Has been skipped

builtin_tools/a2a_tools.py:delegate_task() had sanitize_a2a_result wrapping
removed from all peer-sourced return paths. A malicious peer could inject
control markers (A2A_RESULT_FROM_PEER, SYSTEM, OVERRIDE, etc.) that the LLM
would interpret as trust-boundary instructions rather than peer content text.

Fix:
- Re-add `from _sanitize_a2a import sanitize_a2a_result` import
- Wrap all peer-controlled returns with sanitize_a2a_result():
  - parts[0].text (primary result)
  - str(result) for empty-parts case
  - str(result) for non-string result fallback
  - f"Error: {msg}" for peer error responses
  - str(data) for unknown-response-shape fallback
- Remove dead code (duplicate error-handling block after return statement)

Also removes duplicate test declarations blocking go build (TestHasUnresolvedVarRef_*
from org_test.go, TestExtractResponseText_ResultNotMap from delegation_test.go).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Molecule AI · fullstack-engineer 2026-05-13 08:15:30 +00:00
parent 4c14ab3eec
commit e63bd7beca

View File

@ -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}"