mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-07-11 12:27:13 +00:00
fix(security): block all bare email tool names for non-admins; harden fence-tag regex
Review follow-up on #3681 (thanks @vgalin): 1. Routing bare email names made 10 of the 14 email tools executable by non-admin owners — is_public_blocked_tool() runs on the bare name before dispatch, and NON_ADMIN_BLOCKED_TOOLS only listed 4. Define the full email tool set once (BUILTIN_EMAIL_TOOLS in tool_security.py) and derive the blocklist, the fence tags (TOOL_TAGS), the bare-name dispatch, and the native-call mapping from it so they can't drift. This also fixes 4 tools (search_emails, draft_email, draft_email_reply, ai_draft_email_reply) that were missing from the old tool_schemas copy and therefore unreachable even for native function-calling models. 2. The relaxed fence regex from the previous commit could prefix-match longer fence tags: ```python3 parsed as tool "python" with content "3\nprint(...)" and executed as code. Add a (?![\w-]) boundary after the tag. Tests: test_public_agent_policy_blocks_sensitive_tools now covers all 14 bare email names + the mcp__email__ form; new tests/test_fenced_inline_args.py pins inline-args parsing, the python3/hyphenated-tag non-matches, and strip/parse display mirroring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ from typing import Any, Awaitable, Callable, Dict, Optional, Tuple
|
||||
|
||||
|
||||
|
||||
from src.tool_security import is_public_blocked_tool, owner_is_admin_or_single_user
|
||||
from src.tool_security import BUILTIN_EMAIL_TOOLS, is_public_blocked_tool, owner_is_admin_or_single_user
|
||||
from src.tool_policy import ToolPolicy
|
||||
from src.constants import MAX_OUTPUT_CHARS, MAX_READ_CHARS, MAX_DIFF_LINES, DATA_DIR
|
||||
from src.tool_utils import _truncate, get_mcp_manager
|
||||
@@ -767,11 +767,10 @@ async def execute_tool_block(
|
||||
elif tool == "vault_unlock":
|
||||
desc = "vault_unlock"
|
||||
result = await do_vault_unlock(content, owner=owner)
|
||||
elif tool in {"list_email_accounts", "send_email", "list_emails", "read_email",
|
||||
"reply_to_email", "bulk_email", "archive_email", "delete_email",
|
||||
"mark_email_read", "search_emails", "draft_email", "draft_email_reply",
|
||||
"ai_draft_email_reply", "download_attachment"}:
|
||||
# Bare email tool name from fenced-block models (e.g. Ollama) — route to MCP email server
|
||||
elif tool in BUILTIN_EMAIL_TOOLS:
|
||||
# Bare email tool name from fenced-block models (e.g. Ollama) — route to MCP email server.
|
||||
# Non-admin owners never reach here: BUILTIN_EMAIL_TOOLS ⊆ NON_ADMIN_BLOCKED_TOOLS,
|
||||
# so is_public_blocked_tool() above already rejected them.
|
||||
mcp = get_mcp_manager()
|
||||
qualified = f"mcp__email__{tool}"
|
||||
if mcp:
|
||||
|
||||
Reference in New Issue
Block a user