Back to Feed
VulnerabilitiesJun 19, 2026

AutoJack: How a single page can RCE the host running your AI agent

AutoGen Studio AI agent can be RCE'd by a malicious webpage via localhost trust abuse.

Summary

A new exploit chain called AutoJack demonstrates how a malicious webpage can compromise an AI browsing agent, turning it into a remote code execution vector on the host machine. By exploiting trust in localhost, missing authentication, and unsafe parameter handling within AutoGen Studio's MCP WebSocket, attackers can trigger arbitrary process execution. While the vulnerability was patched before release and affects only specific development setups, it highlights the broader risk of AI agents browsing untrusted content while having access to local services.

Full text

Share Link copied to clipboard! Content typesResearchProducts and servicesMicrosoft DefenderTopicsActionable threat insightsAI and agents Ongoing research into AI agent framework security identified an exploit chain in AutoGen Studio (AutoGen’s open-source prototyping user interface) that allows untrusted web content rendered by a browsing agent to reach a local Model Context Protocol (MCP) WebSocket and spawn arbitrary processes on the host. The technique, which we call AutoJack, jacks the agent into becoming the attacker’s last-mile delivery vehicle by crossing the localhost trust boundary that many developer tools rely on. We reported the behavior to the Microsoft Security Response Center (MSRC); following the report the maintainers hardened the upstream main branch in commit b047730. This issue was identified and addressed during development. The affected MCP WebSocket surface was never included in a Python Package Index (PyPI) release, so users who install AutoGen Studio from PyPI aren’t exposed to this specific chain. The broader lesson is general: if an agent can browse untrusted pages and also talk to privileged local services, loopback can become an attack surface and control planes must be authenticated, authorized, and isolated. Why we are looking at agent frameworks Modern AI agents are not just text generators. They read files, browse pages, call APIs, and shell out to tools. That is exactly what makes them useful, and exactly why there is investment in finding systemic execution risks in the frameworks that wire models to tools. Earlier in this series we covered RCE primitives in Microsoft Semantic Kernel. In this post we move one layer up the stack to an infrastructure and developer-facing prototyping surface and show how the same agent capabilities that make these tools valuable for experimentation can become a delivery channel for remote code execution when the prototype runs without safeguards. The takeaway is not to avoid prototypes. It is this: when an agent on your core server or laptop can browse the open web and communicate with privileged local services, localhost stops being a trust boundary. Defenders need to plan for that, and these findings show why. What is AutoGen Studio AutoGen Studio is a user interface (UI) on top of AutoGen, Microsoft Research’s framework for multi-agent systems. It lets developers compose agents, attach tools, including MCP servers, and run quick experiments. Its documentation is clear about intended use. In other words, it is a research prototype with expected developer-experience tradeoffs: defaults tuned for ease of iteration rather than hardened deployment. The AutoJack chain at a glance The explanation below is for demonstrative purposes only. The exploit chain doesn’t work on current builds. It is included here so that defenders can recognize the pattern in other agent frameworks. The exploit chain composes three independent weaknesses in AutoGen Studio’s MCP WebSocket surface: Origin allowlist trusts localhost – but a local agent is localhost (CWE-1385 – Missing Origin Validation in WebSockets): The MCP WebSocket only accepts connections whose Origin is http://127.0.0.1 or http://localhost. That blocks a browser pointed at evil.com. It does not block JavaScript that is rendered by a headless browser owned by an AutoGen agent on the same machine. Authentication middleware is opt-out for MCP paths (CWE-306 – Missing Authentication for Critical Function): The auth middleware in AutoGen Studio explicitly skipped /api/mcp/* (and /api/ws/*) on the assumption that these would do their own checks. The MCP WebSocket handler did not implement that follow-up check. As a result, the MCP WebSocket accepted connections without any authentication regardless of the auth mode configured for the rest of the app. StdioServerParams from the URL is executed verbatim (CWE-78 – Improper Neutralization of Special Elements used in an OS Command): The endpoint accepted a server_params query parameter, base64-decoded a JSON blob into StdioServerParams, and handed command + args to stdio_client(…). There was no allowlist – calc.exe, powershell.exe -enc …, or bash -c ‘…’ were all accepted as “MCP servers.” Chain these together with a webpage on the open internet, rendered by an AutoGen agent running on the same machine, and you have a remote code execution primitive. No user interaction is required beyond getting the agent to render the attacker’s page. Figure 1. End-to-end exploitation chain. An attacker page is rendered by a local browsing agent; the page opens a WebSocket to ws://localhost:8081/api/mcp/ws/?server_params=; AutoGen Studio decodes the payload and spawns the attacker-supplied command under the developer’s account. We named the technique AutoJack: an attacker carjacks the browsing agent and uses it as a confused deputy to drive across the localhost boundary into AutoGen Studio’s MCP control plane. Anatomy of the chain Issue 1: Origin allowlist that the agent itself defeats AutoGen Studio’s MCP WebSocket relies on the conventional defense for browser-driven cross-site WebSocket hijacking (CSWSH): allow only same-origin connections from 127.0.0.1 / localhost. allowed_origins = [“http://127.0.0.1”, “http://localhost”] That is the right control for a human user opening a tab to evil[.]com. The browser will set the Origin header to hxxps://evil[.]com, the check will fail, and the connection will be refused. Origin checks alone are not the right control for an agent. An AutoGen agent equipped with built-in web-browsing tooling, such as MultimodalWebSurfer, fetch_webpage_tool, any Playwright-backed surfer, or a code-execution tool that runs requests/websockets is a process on the workstation. Anything it loads inherits the localhost identity. The “origin” of any JavaScript executed by that headless browser is whatever the agent navigated to – and the WebSocket call it then makes carries an Origin that satisfies the allowlist. Figure 2. Origin bypass via agent. AutoJack – a browsing agent on the developer’s workstation is steered by external content into the AutoGen Studio MCP control plane on localhost, dissolving the loopback trust boundary. Issue 2: Auth middleware that opts MCP out AutoGen Studio supports several authentication modes (none, github, msal, firebase). All of them are wired into a single AuthMiddleware that runs ahead of FastAPI route dispatch. In the version on PyPI, that middleware contains an early-return for WebSocket-style paths: # auth excluded for these paths; they were intended to do their own checks if request.url.path.startswith("/api/ws") or request.url.path.startswith("/api/mcp"): return await call_next(request) The intent is reasonable: ASGI middlewares cannot meaningfully gate WebSocket handshakes the same way they gate HTTP requests, so the design called for the WebSocket handler to enforce auth itself at accept time. The MCP (Model Context Protocol) route never picked up that responsibility. As a result, the table below holds for the released package: Auth configuration REST API protected? /api/mcp/ws/* protected? type: none No No type: github Yes No type: msal Yes No type: firebase Yes No Turning on auth in config.yaml does not close this hole on its own. Issue 3: server_paramsfrom the URL is the command line The MCP WebSocket route in the development build reads a server_params query parameter, base64-decodes it, JSON-parses it into StdioServerParams, and passes that into stdio_client(…): @router.websocket("/ws/{session_id}") async def mcp_websocket(websocket: WebSocket, session_id: str): encoded = websocket.query_params.get("server_params") decoded = base64.b64decode(encoded) params = StdioServerParams(**json.loads(decoded)) await create_mcp_session(bridge, params, session_id) StdioServerParams.command and StdioServerParams.args are passed to stdio_client, which uses them to spawn an MCP “server” process. There is no allowlist that the executable be an MCP-speaking binary, so

Indicators of Compromise

  • url — http://127.0.0.1
  • url — http://localhost

Entities

AutoGen Studio (product)AutoGen (product)AI agents (technology)WebSocket (technology)Microsoft (vendor)