From 2d9975f09a0dd52119c044e50c1797a67b1271e7 Mon Sep 17 00:00:00 2001 From: Zamil Majdy Date: Fri, 13 Feb 2026 21:48:59 +0400 Subject: [PATCH] feat(backend/sdk): enable WebSearch, block WebFetch, consolidate tool constants - Add WebSearch (Brave Search via Anthropic API) to allowed SDK built-in tools - Explicitly block WebFetch (SSRF risk) via SDK_DISALLOWED_TOOLS - Consolidate all tool security constants into tool_adapter.py (single source of truth) --- .../api/features/chat/sdk/security_hooks.py | 42 +++--------------- .../backend/api/features/chat/sdk/service.py | 3 +- .../api/features/chat/sdk/tool_adapter.py | 43 ++++++++++++++++++- 3 files changed, 50 insertions(+), 38 deletions(-) diff --git a/autogpt_platform/backend/backend/api/features/chat/sdk/security_hooks.py b/autogpt_platform/backend/backend/api/features/chat/sdk/security_hooks.py index 14efc6d459..89853402a3 100644 --- a/autogpt_platform/backend/backend/api/features/chat/sdk/security_hooks.py +++ b/autogpt_platform/backend/backend/api/features/chat/sdk/security_hooks.py @@ -11,45 +11,15 @@ import re from collections.abc import Callable from typing import Any, cast -from backend.api.features.chat.sdk.tool_adapter import MCP_TOOL_PREFIX +from backend.api.features.chat.sdk.tool_adapter import ( + BLOCKED_TOOLS, + DANGEROUS_PATTERNS, + MCP_TOOL_PREFIX, + WORKSPACE_SCOPED_TOOLS, +) logger = logging.getLogger(__name__) -# Tools that are blocked entirely (CLI/system access). -# "Bash" (capital) is the SDK built-in — it's NOT in allowed_tools but blocked -# here as defence-in-depth. The agent uses mcp__copilot__bash_exec instead, -# which has kernel-level network isolation (unshare --net). -BLOCKED_TOOLS = { - "Bash", - "bash", - "shell", - "exec", - "terminal", - "command", -} - -# Tools allowed only when their path argument stays within the SDK workspace. -# The SDK uses these to handle oversized tool results (writes to tool-results/ -# files, then reads them back) and for workspace file operations. -WORKSPACE_SCOPED_TOOLS = {"Read", "Write", "Edit", "Glob", "Grep"} - -# Dangerous patterns in tool inputs -DANGEROUS_PATTERNS = [ - r"sudo", - r"rm\s+-rf", - r"dd\s+if=", - r"/etc/passwd", - r"/etc/shadow", - r"chmod\s+777", - r"curl\s+.*\|.*sh", - r"wget\s+.*\|.*sh", - r"eval\s*\(", - r"exec\s*\(", - r"__import__", - r"os\.system", - r"subprocess", -] - def _deny(reason: str) -> dict[str, Any]: """Return a hook denial response.""" diff --git a/autogpt_platform/backend/backend/api/features/chat/sdk/service.py b/autogpt_platform/backend/backend/api/features/chat/sdk/service.py index 65195b442c..65c4cebb06 100644 --- a/autogpt_platform/backend/backend/api/features/chat/sdk/service.py +++ b/autogpt_platform/backend/backend/api/features/chat/sdk/service.py @@ -41,6 +41,7 @@ from .response_adapter import SDKResponseAdapter from .security_hooks import create_security_hooks from .tool_adapter import ( COPILOT_TOOL_NAMES, + SDK_DISALLOWED_TOOLS, LongRunningCallback, create_copilot_mcp_server, set_execution_context, @@ -543,7 +544,7 @@ async def stream_chat_completion_sdk( "system_prompt": system_prompt, "mcp_servers": {"copilot": mcp_server}, "allowed_tools": COPILOT_TOOL_NAMES, - "disallowed_tools": ["Bash"], + "disallowed_tools": SDK_DISALLOWED_TOOLS, "hooks": security_hooks, "cwd": sdk_cwd, "max_buffer_size": config.claude_agent_max_buffer_size, diff --git a/autogpt_platform/backend/backend/api/features/chat/sdk/tool_adapter.py b/autogpt_platform/backend/backend/api/features/chat/sdk/tool_adapter.py index d983d5e785..2d259730bf 100644 --- a/autogpt_platform/backend/backend/api/features/chat/sdk/tool_adapter.py +++ b/autogpt_platform/backend/backend/api/features/chat/sdk/tool_adapter.py @@ -310,7 +310,48 @@ def create_copilot_mcp_server(): # Bash is NOT included — use the sandboxed MCP bash_exec tool instead, # which provides kernel-level network isolation via unshare --net. # Task allows spawning sub-agents (rate-limited by security hooks). -_SDK_BUILTIN_TOOLS = ["Read", "Write", "Edit", "Glob", "Grep", "Task"] +# WebSearch uses Brave Search via Anthropic's API — safe, no SSRF risk. +_SDK_BUILTIN_TOOLS = ["Read", "Write", "Edit", "Glob", "Grep", "Task", "WebSearch"] + +# SDK built-in tools that must be explicitly blocked. +# Bash: dangerous — agent uses mcp__copilot__bash_exec with kernel-level +# network isolation (unshare --net) instead. +# WebFetch: SSRF risk — can reach internal network (localhost, 10.x, etc.). +# Agent uses the SSRF-protected mcp__copilot__web_fetch tool instead. +SDK_DISALLOWED_TOOLS = ["Bash", "WebFetch"] + +# Tools that are blocked entirely in security hooks (defence-in-depth). +# Includes SDK_DISALLOWED_TOOLS plus common aliases/synonyms. +BLOCKED_TOOLS = { + *SDK_DISALLOWED_TOOLS, + "bash", + "shell", + "exec", + "terminal", + "command", +} + +# Tools allowed only when their path argument stays within the SDK workspace. +# The SDK uses these to handle oversized tool results (writes to tool-results/ +# files, then reads them back) and for workspace file operations. +WORKSPACE_SCOPED_TOOLS = {"Read", "Write", "Edit", "Glob", "Grep"} + +# Dangerous patterns in tool inputs +DANGEROUS_PATTERNS = [ + r"sudo", + r"rm\s+-rf", + r"dd\s+if=", + r"/etc/passwd", + r"/etc/shadow", + r"chmod\s+777", + r"curl\s+.*\|.*sh", + r"wget\s+.*\|.*sh", + r"eval\s*\(", + r"exec\s*\(", + r"__import__", + r"os\.system", + r"subprocess", +] # List of tool names for allowed_tools configuration # Include MCP tools, the MCP Read tool for oversized results,