flawopen.com/Incidents/microsoft-autogen-studio-autojack-agent-rce-june-2026
●
Microsoft AutoGen project · CWE-1385 / CWE-306 / CWE-78 · 2026-06-18 · 高危
安全研究 · FlawOpen
AutoJack:AutoGen Studio 的 RCE 研究链
Microsoft在AutoGen Studio开发构建中发现通过本地MCP触发的RCE研究链。该问题在发布前修复,未进入PyPI软件包。[1], [2]
💡 通俗易懂的原理解析 (ELI5)
想象一个研究实验室:助手负责阅读访客留下的便条。因为助手在同一栋楼工作,它可以进入控制室。前台对这间房免除了常规身份检查,访客的便条还能指定启动哪种工具。AutoJack 把这些捷径串在一起:浏览代理显示了不可信内容,内容触达 AutoGen Studio 本机的 MCP 控制平面,调用者提供的设置可能导致子进程启动。应为控制平面启用身份验证,把启动设置移出 WebSocket URL,并将助手与开发者工作站隔离。Microsoft 称该问题在 PyPI 发布前已于上游分支修复。该研究针对的是发布前的源代码,而非受影响的客户版本。[1]
核心概念与专有名词
Loopback / localhost- 用于访问本机服务的网络接口。它限制外部网络访问,但不会将本机进程(例如代理的浏览器)与同一主机上的其他服务隔离。[1]
WebSocket Origin 验证- 服务器在 WebSocket 握手期间检查 Origin 标头。Microsoft 发现,在其测试的代理流程中,这项检查本身无法阻止渲染的网页触达本地 MCP 服务。[1], [3]
StdioServerParams- AutoGen 的 MCP stdio 配置,包含启动服务器进程所用的程序和参数。报告中的路由会从 WebSocket URL 参数解码这些设置。[1], [2], [5]
Confused deputy- 攻击者诱使有权限的组件替不可信方使用自身权限。此处,浏览代理和本地 Studio 服务把网页内容连接到了主机进程启动操作。[1]
框架映射
- 本指南所述弱点的 CWE 参考: CWE-78 CWE-306 CWE-1385
- OWASP GenAI 2025 — LLM06:2025 过度代理权限
事件演进时间线
2026-06-18 之前
2026-06-18
Microsoft 发布 AutoJack 研究和缓解建议。报告描述的是受控的本地演示,并非针对客户的已确认攻击。[1]
攻击执行流程分解
步骤 1
代理被要求浏览不可信内容
提示、检索到的网页或其他不可信输入使 AutoGen 浏览代理在运行 AutoGen Studio 的同一台工作站上显示攻击者控制的页面。[1]
步骤 2
步骤 3
步骤 4
源代码对比:漏洞与安全实现
易受攻击的示例会解析调用者控制的启动设置,但特意不启动进程。上游修复将设置移出 WebSocket 查询,存入服务器端的一次性会话状态,并恢复 MCP 路由的身份验证。此防御模式还增加了过期时间、大小限制、并发锁和可执行程序允许列表;请将示例名称替换为明确批准的 MCP 二进制文件。它不能替代 Origin 验证或操作系统隔离。[1], [2]
存在漏洞的实现
import base64
import json
from dataclasses import dataclass
@dataclass(frozen=True)
class StdioServerParams:
command: str
args: tuple[str, ...]
def params_from_websocket_query(query: dict[str, str]) -> StdioServerParams:
# 开发路由信任 URL 中提供的配置。
encoded = query["server_params"]
decoded = base64.b64decode(encoded)
return StdioServerParams(**json.loads(decoded))加固后的安全修复
from dataclasses import dataclass
from threading import Lock
from time import monotonic
from uuid import uuid4
@dataclass(frozen=True)
class StdioServerParams:
command: str
args: tuple[str, ...]
SESSION_TTL = 30.0
MAX_PENDING = 256
ALLOWED_COMMANDS = {"approved-mcp-server"}
pending: dict[str, tuple[float, StdioServerParams]] = {}
pending_lock = Lock()
def register_params(params: StdioServerParams, authenticated: bool) -> str:
# authenticated 必须来自经过验证的中间件,不能来自请求数据。
if not authenticated:
raise PermissionError("MCP control-plane authentication required")
if params.command not in ALLOWED_COMMANDS:
raise ValueError("unapproved MCP server executable")
now = monotonic()
with pending_lock:
for key, (expires, _) in list(pending.items()):
if expires <= now:
pending.pop(key, None)
if len(pending) >= MAX_PENDING:
raise RuntimeError("pending MCP session limit reached")
session_id = str(uuid4())
pending[session_id] = (now + SESSION_TTL, params)
return session_id
def consume_params(session_id: str, authenticated: bool) -> StdioServerParams:
if not authenticated:
raise PermissionError("MCP control-plane authentication required")
with pending_lock:
entry = pending.pop(session_id, None)
if entry is None or entry[0] <= monotonic():
raise ValueError("unknown or expired MCP session")
return entry[1]工程与系统安全加固清单
- ✓对 MCP 控制平面的每条路由(包括 WebSocket 握手)执行身份验证和授权;针对这些路由测试已配置的每种身份验证模式。[1], [2], [4]
- ✓不要在 WebSocket URL 或其他浏览器可控输入中接收进程启动配置;通过已验证的请求注册配置,并将其绑定到短时、单次使用的服务器端会话。[2]
- ✓让待处理会话过期、限制其数量、以原子方式消费每个会话,并拒绝未知、过期或重放的标识符。[2]
- ✓仅允许经过批准的 MCP 服务器程序和固定参数结构;不要让模型输出或页面内容选择任意程序。[1], [5]
- ✓将会渲染不可信页面的浏览代理与特权本地控制平面隔离;条件允许时,在浏览器沙箱中阻止 loopback 访问。[1], [3]
- ✓让代理和 Studio 以低权限身份或一次性 VM/容器运行,并针对代理运行时启动意外子进程生成告警。[1]
- ✓从源码构建 AutoGen Studio 时,使用 b047730 或之后的版本。Microsoft 表示,当时的 PyPI 包不包含受影响路由;应核验实际部署的构建产物。[1], [2]