{"uuid": "7e59eab2-eb0b-4661-b2c8-6976fb98d2cc", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-55646", "type": "seen", "source": "https://gist.github.com/Correctover/dcf89533dd8acf055791178f2130e704", "content": "# CVE Audit: Google ADK MCP Tool Execution \u2014 Fail-Open Architecture\n\n## Summary\n\n**Framework**: Google Agent Development Kit (ADK) v2026  \n**Component**: `src/google/adk/tools/mcp_tool/mcp_tool.py`  \n**Vulnerability**: CWE-636 \u2014 Fail-Open Error Handling in MCP Tool Execution  \n**Severity**: High (CVSS 8.6 estimated)  \n**Related**: CVE-2026-55646 (Microsoft AGT, CVSS 9.1)\n\n## Vulnerability Details\n\n### Location 1: Default Path (Feature Flag OFF)\n\n```python\n# mcp_tool.py, run_async() method\nif not is_feature_enabled(FeatureName._MCP_GRACEFUL_ERROR_HANDLING):\n    # Pre-fix behavior: exceptions bubble up to the agent runner.\n    return await super().run_async(args=args, tool_context=tool_context)\n```\n\n**Problem**: When the feature flag is disabled (default), there is NO error boundary. MCP exceptions propagate directly to the agent runner, potentially leaving the agent in an inconsistent state. No output verification occurs.\n\n### Location 2: \"Fixed\" Path (Feature Flag ON)\n\n```python\n# When feature flag is enabled:\ntry:\n    return await super().run_async(args=args, tool_context=tool_context)\nexcept McpError as e:\n    logger.warning(\"MCP tool execution failed with McpError: %s\", e)\n    return {\"error\": f\"MCP tool execution failed: {e}\"}\nexcept Exception as e:\n    logger.warning(\"Unexpected error during MCP tool execution: %s\", e, exc_info=True)\n    return {\"error\": f\"Unexpected error during MCP tool execution: {e}\"}\n```\n\n**Problem**: The \"fix\" catches exceptions and returns an error dict as tool output. The agent treats `{\"error\": \"...\"}` as a valid tool result and proceeds with decision-making based on an error state \u2014 not on verified output. This is **structurally fail-open**.\n\n### Location 3: Pre-Fix Hang Vulnerability\n\n```python\n# In _run_async_impl, when feature flag is OFF:\nresponse = await call_coro  # Can hang for ~300s (sse_read_timeout default)\n```\n\nWhen the transport crashes (e.g., non-2xx HTTP response from API gateway), the tool call hangs for the full `sse_read_timeout` duration (~5 minutes) before surfacing the failure. The feature flag \"fix\" adds `asyncio.wait` with the session's background task, but only when enabled.\n\n## Attack Scenario\n\n```\n1. Agent calls MCP tool (e.g., payment processing)\n2. MCP server returns malformed/error response\n3. Feature flag OFF: exception propagates, agent state corrupted\n   OR\n   Feature flag ON: {\"error\": \"...\"} returned as valid output\n4. Agent's LLM sees unexpected output format\n5. Agent retries tool call \u2192 duplicate side effects\n6. No idempotency guard at MCP boundary\n7. Financial/state corruption propagates downstream\n```\n\n## Impact\n\n- **Data integrity**: Agent decisions based on unvalidated/corrupted tool output\n- **Idempotency**: Retries on error output cause duplicate side effects\n- **Availability**: 5-minute hang when transport crashes (default behavior)\n- **Audit trail**: Decision ledger records decisions on corrupted premises\n\n## MCP Ecosystem Context\n\n| Metric | Value | Source |\n|--------|-------|--------|\n| MCP downloads | 150M+ | npm registry |\n| MCP servers with zero auth | 40.55% | arXiv 2605.22333 |\n| OAuth implementations defective | 100% | MCP spec audit |\n| CVEs assigned | 10+ | MITRE/CVE |\n| Anthropic response | \"Expected behavior\" | Public |\n\n## Fix Recommendation\n\n```python\n# Fail-closed: block execution on MCP failure\nasync def run_async(self, *, args, tool_context):\n    try:\n        result = await super().run_async(args=args, tool_context=tool_context)\n        # Verify output integrity before returning\n        if not self._verify_output(result):\n            raise ToolOutputCorruptedError(\n                f\"Tool {self.name} returned non-conforming output\"\n            )\n        return result\n    except (McpError, ToolOutputCorruptedError) as e:\n        # FAIL-CLOSED: do NOT return error as output\n        # Instead, request agent to halt and escalate\n        tool_context.request_confirmation(\n            hint=f\"Tool {self.name} verification failed: {e}. Do not proceed.\"\n        )\n        raise\n```\n\n## Related Work\n\n- CVE-2026-55646: Same pattern in Microsoft AGT (CVSS 9.1)\n- CCS v1.0: Protocol-level output verification standard (https://doi.org/10.5281/zenodo.21234580)\n- CrewAI PR #6492: Idempotency guard for tool retries\n\n## Disclosure Timeline\n\n- 2026-07-09: Vulnerability discovered during routine audit\n- 2026-07-09: Public disclosure (this document)\n- 2026-07-09: Posted to google/adk-python#6099 and #3940\n- Coordination: Pending Google security response\n\n---\n\n**Author**: Correctover  \n**License**: CC BY 4.0  \n**CCS SDK**: `pip install correctover-ccs` | `npm install correctover-ccs`\n", "creation_timestamp": "2026-07-09T15:03:14.406217Z"}