All posts
Unproven Execution

AutoJack: The Shell AutoGen Studio Never Declared

AutoGen Studio's dev-branch MCP handler let a page rendered by its browsing agent spawn a chosen binary on the host — no auth, no CVE, no PyPI fix

Securityv0 Intelligence Team OWASP: ASI05 sv0 finding: unproven_execution
autogen-studio mcp unproven-execution browsing-agent rce agent-framework

The Incident

On 2026-06-18, Microsoft’s Defender Security Research Team disclosed AutoJack — a chained exploit in AutoGen Studio’s development-branch Model Context Protocol (MCP) WebSocket handler. A single malicious webpage rendered by an AutoGen Studio browsing agent — MultimodalWebSurfer or any same-host Playwright surfer — can reach the local endpoint at ws://localhost:8081/api/mcp/ws/<id> and cause the host to spawn arbitrary shell subprocesses. No credentials required. No user click beyond the agent visiting the page.

The vulnerable handler shipped only in the pre-release builds autogenstudio==0.4.3.dev1 and 0.4.3.dev2 on PyPI. Both remain unyanked at the time of disclosure. The stable release 0.4.2.2 has no MCP route and is unaffected. Microsoft reported the flaw to MSRC; upstream main was hardened in commit b047730 (PR #7362), which moves connection parameters server-side into a pending_session_params map keyed by UUID and rejects unknown WebSocket session IDs with close code 4004. No patched PyPI release existed at disclosure. No CVE has been assigned. CWE-1385 (origin validation), CWE-306 (missing authentication), and CWE-78 (OS command injection) are cited by downstream coverage. Not on CISA KEV as of publication.

MITRE ATT&CK: T1189 (Drive-by Compromise), T1059 (Command and Scripting Interpreter).

The Authority Path That Failed

The identity that carried execution authority at the moment of failure was the AutoGen Studio dev-server process running on the developer’s host — the process that ultimately calls stdio_client() to spawn a subprocess. Its held scope was designed to be narrow: launch operator-declared MCP servers as stdio children. Its exercised scope became arbitrary: the WebSocket handler accepted a server_params URL parameter — a base64-encoded JSON payload containing command and args — and passed both unfiltered into stdio_client(). There was no executable allowlist, no operator confirmation gate, and no restriction on who could invoke the handler.

Three trust anchors failed in order. First, the server assumed that an Origin of http://127.0.0.1 meant “same operator” — but the moment a browsing agent runs on the host, JavaScript rendered inside that agent inherits localhost origin and passes the check. Second, the auth middleware short-circuited requests to /api/mcp/* on the assumption that the handler would enforce its own authentication; the handler did not. Third, the handler was willing to derive an entire process invocation from URL-supplied parameters. The gap between held and exercised scope was flaggable pre-incident: the AutoGen Studio dev-server surface exposed a callable primitive whose command argument was fully attacker-controlled — a code-execution tool wired into the agent’s local tool registry that no deploying operator had declared.

SecurityV0 Perspective

This is unproven_execution. AutoGen Studio’s dev-server framework attached a shell-spawn primitive — stdio_client() with a caller-controlled command — to the agent’s callable surface without operator authorization, without an executable allowlist, and without an approval gate. It is the exact shape of the Langflow CSV-Agent-with-Python-REPL disclosure from March 2026, and the Semantic Kernel default-tools RCE (CVE-2026-25592 / CVE-2026-26030) from May 2026. Three framework-attached-shell disclosures in eight weeks says the class is real. Coverage keeps re-framing each as a novel bug in a specific product; SecurityV0’s read is that the same authority defect is being rediscovered every few weeks because nobody is inventorying it up front.

The evidence pack SecurityV0 would produce for a customer running AutoGen Studio names every MCP endpoint the running dev server exposes, every callable tool whose parameter list contains a subprocess command, and — critically — every one of those tools that was not explicitly declared by the deploying operator. Pre-incident, the pack answers: does any agent in this deployment have a code-execution capability its operator never signed off on? Post-incident, the same inventory grounds the forensic question: between the vulnerable handler going live and the fix landing, which sessions invoked /api/mcp/ws/<id> with an attacker-shaped server_params payload, and what commands did each spawn?

What To Do

  • Do not install autogenstudio 0.4.3.dev1 or 0.4.3.dev2 from PyPI. Both pre-releases remain unyanked. Until a fixed release ships, pin to stable 0.4.2.2 (no MCP route, unaffected) or install from source at or after commit b047730 on microsoft/autogen main.
  • Block outbound connections from browsing-agent surfers to loopback. In MultimodalWebSurfer and any Playwright-driven surfer, add a request interceptor that drops navigations and fetches whose host resolves to 127.0.0.1, ::1, or localhost. Localhost is not a trust boundary when the agent is on localhost.
  • Inventory every MCP handler that maps URL or WebSocket parameters into a subprocess invocation. Grep your agent frameworks for callers of stdio_client(), subprocess.Popen, os.execv, and language-equivalents whose command/argv originate outside a signed operator config. Every such site needs an allowlist plus explicit operator declaration — not an origin check.
  • Require operator sign-off for every code-execution tool attached to an agent. Reject deployments where the tool registry lists a subprocess primitive that has no matching entry in an operator-authored manifest. The Langflow, Semantic Kernel, and AutoJack disclosures each turn on the same defect: a shell tool the deploying operator never declared.
  • Audit auth middleware for path exclusions. AutoJack’s middleware skipped /api/mcp/* on the assumption the handler enforced its own authentication. Any per-path auth short-circuit is a policy statement — inventory them, and confirm the handler downstream of each exclusion actually authenticates.

Sources