fix: display assistant content with finish tool call + block shell write redirects
Bug 1: Assistant text content was silently dropped when the LLM response included both content and tool calls (e.g. finish with a summary). Now content is displayed before tool call execution regardless. Bug 2: Shell redirect operators (>, >>, <<) allowed bypassing file-write permissions when the base command (e.g. cat) was in the allowed list. Redirects now require explicit user approval in permissions, and the shell tool itself blocks them as defense-in-depth. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import shlex
|
||||
from collections.abc import Awaitable, Callable
|
||||
|
||||
@@ -14,6 +15,9 @@ logger = logging.getLogger(__name__)
|
||||
# Type alias for the async prompt callback
|
||||
PromptCallback = Callable[[str, str], Awaitable[bool]]
|
||||
|
||||
# Detect shell redirects that write to files (>, >>, heredocs)
|
||||
_WRITE_REDIRECT_PATTERN = re.compile(r"(?:>\s*\S|>>|<<)")
|
||||
|
||||
|
||||
class PermissionDenied(Exception):
|
||||
"""Raised when a tool is denied execution by permissions policy."""
|
||||
@@ -104,6 +108,11 @@ class PermissionsService:
|
||||
logger.info("Shell command '%s' matches denied prefix '%s'", cmd, denied)
|
||||
return False
|
||||
|
||||
# Detect shell redirects that write to files — require approval
|
||||
if _WRITE_REDIRECT_PATTERN.search(cmd):
|
||||
logger.info("Shell command '%s' contains file-write redirect — requiring approval", cmd)
|
||||
return None # fall through to user prompt
|
||||
|
||||
# Allowed commands: base executable match
|
||||
if shell_config.allowed_commands:
|
||||
if base_cmd in shell_config.allowed_commands:
|
||||
|
||||
Reference in New Issue
Block a user