From 59fa9fdeaa0e29a3e8f1fe05c54179f73e30defc Mon Sep 17 00:00:00 2001 From: Soulter <905617992@qq.com> Date: Mon, 27 Apr 2026 02:07:52 +0800 Subject: [PATCH 1/3] fix(core): security fix - restrict send_message_to_user to current session only Closes #7822 SECURITY: Remove the user-controlled 'session' parameter from the send_message_to_user tool. Previously, a regular user could ask the LLM to send messages to any arbitrary session (group chat) by providing a crafted session string, which is a high-risk vulnerability. Changes: - Remove 'session' parameter from tool schema (LLM can no longer propose it) - Always use context.context.event.unified_msg_origin as the target session - Update description to clearly state that messages can only be sent to the current user's session --- astrbot/core/tools/message_tools.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/astrbot/core/tools/message_tools.py b/astrbot/core/tools/message_tools.py index 31e7ba9041..5f5fcc8523 100644 --- a/astrbot/core/tools/message_tools.py +++ b/astrbot/core/tools/message_tools.py @@ -23,10 +23,12 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): name: str = "send_message_to_user" description: str = ( - "Send message to the user. " + "Send message to the current user/session. " "Supports various message types including `plain`, `image`, `record`, `video`, `file`, and `mention_user`. " "Use this tool to send media files (`image`, `record`, `video`, `file`), " - "or when you need to proactively message the user(such as cron job). For normal text replies, you can output directly." + "or when you need to proactively message the user (such as cron job). " + "For normal text replies, you can output directly. " + "This tool always sends the message to the current user's session and CANNOT send to other sessions." ) parameters: dict = Field( default_factory=lambda: { @@ -65,10 +67,6 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): "required": ["type"], }, }, - "session": { - "type": "string", - "description": "Optional. Target session string. Defaults to current session.", - }, }, "required": ["messages"], } @@ -117,7 +115,11 @@ async def _resolve_path_from_sandbox( async def call( self, context: ContextWrapper[AstrAgentContext], **kwargs ) -> ToolExecResult: - session = kwargs.get("session") or context.context.event.unified_msg_origin + # SECURITY FIX: Always use the current session (the user who triggered the tool). + # Previously, the tool accepted a user-controlled "session" parameter, which allowed + # attackers to send arbitrary messages to arbitrary sessions (groups/chats). + # See https://github.com/AstrBotDevs/AstrBot/issues/7822 + session = context.context.event.unified_msg_origin messages = kwargs.get("messages") if not isinstance(messages, list) or not messages: return "error: messages parameter is empty or invalid." From 1063a45665ea392fc9787501f465543a00392e0d Mon Sep 17 00:00:00 2001 From: AstrBot Date: Wed, 29 Apr 2026 00:01:14 +0800 Subject: [PATCH 2/3] fix: restore session param but restrict to admin only - Re-add the parameter removed in the original PR - Non-admin users can only send to their own session (current_session) - Admin users can send to any session via the param - Uses from computer_tools.util (same pattern as fs.py) - Ref: https://github.com/AstrBotDevs/AstrBot/issues/7822 Co-authored-by: Soulter --- astrbot/core/tools/message_tools.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/astrbot/core/tools/message_tools.py b/astrbot/core/tools/message_tools.py index 5f5fcc8523..f65df0533b 100644 --- a/astrbot/core/tools/message_tools.py +++ b/astrbot/core/tools/message_tools.py @@ -14,6 +14,7 @@ from astrbot.core.computer.computer_client import get_booter from astrbot.core.message.message_event_result import MessageChain from astrbot.core.platform.message_session import MessageSession +from astrbot.core.tools.computer_tools.util import check_admin_permission from astrbot.core.tools.registry import builtin_tool from astrbot.core.utils.astrbot_path import get_astrbot_temp_path @@ -23,12 +24,13 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): name: str = "send_message_to_user" description: str = ( - "Send message to the current user/session. " + "Send message to the user. " "Supports various message types including `plain`, `image`, `record`, `video`, `file`, and `mention_user`. " "Use this tool to send media files (`image`, `record`, `video`, `file`), " "or when you need to proactively message the user (such as cron job). " "For normal text replies, you can output directly. " - "This tool always sends the message to the current user's session and CANNOT send to other sessions." + "Optionally specify a `session` to send the message to a different session (admin only). " + "If no session is specified, the message is sent to the current user's session." ) parameters: dict = Field( default_factory=lambda: { @@ -68,6 +70,10 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): }, }, }, + "session": { + "type": "string", + "description": "Optional. Target session string. Defaults to current session. Only AstrBot admins can send to other sessions.", + }, "required": ["messages"], } ) @@ -115,11 +121,16 @@ async def _resolve_path_from_sandbox( async def call( self, context: ContextWrapper[AstrAgentContext], **kwargs ) -> ToolExecResult: - # SECURITY FIX: Always use the current session (the user who triggered the tool). - # Previously, the tool accepted a user-controlled "session" parameter, which allowed - # attackers to send arbitrary messages to arbitrary sessions (groups/chats). + # Security: only AstrBot admins can send messages to other sessions. + # Non-admin users are always restricted to their own session. # See https://github.com/AstrBotDevs/AstrBot/issues/7822 - session = context.context.event.unified_msg_origin + current_session = context.context.event.unified_msg_origin + session = kwargs.get("session") or current_session + if session != current_session: + if permission_error := check_admin_permission( + context, "Send message to another session" + ): + return permission_error messages = kwargs.get("messages") if not isinstance(messages, list) or not messages: return "error: messages parameter is empty or invalid." From b61149cacd4bb81dc1913d111fdd5561bb3e6864 Mon Sep 17 00:00:00 2001 From: Weilong Liao <37870767+Soulter@users.noreply.github.com> Date: Wed, 29 Apr 2026 00:12:53 +0800 Subject: [PATCH 3/3] Update message_tools.py --- astrbot/core/tools/message_tools.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/astrbot/core/tools/message_tools.py b/astrbot/core/tools/message_tools.py index f65df0533b..177461d944 100644 --- a/astrbot/core/tools/message_tools.py +++ b/astrbot/core/tools/message_tools.py @@ -27,10 +27,7 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): "Send message to the user. " "Supports various message types including `plain`, `image`, `record`, `video`, `file`, and `mention_user`. " "Use this tool to send media files (`image`, `record`, `video`, `file`), " - "or when you need to proactively message the user (such as cron job). " - "For normal text replies, you can output directly. " - "Optionally specify a `session` to send the message to a different session (admin only). " - "If no session is specified, the message is sent to the current user's session." + "or when you need to proactively message the user(such as cron job). For normal text replies, you can output directly." ) parameters: dict = Field( default_factory=lambda: { @@ -69,10 +66,10 @@ class SendMessageToUserTool(FunctionTool[AstrAgentContext]): "required": ["type"], }, }, - }, - "session": { - "type": "string", - "description": "Optional. Target session string. Defaults to current session. Only AstrBot admins can send to other sessions.", + "session": { + "type": "string", + "description": "Optional. Target session string. Defaults to current session.", + }, }, "required": ["messages"], }