6月18日、Microsoft Defender Security Research Teamが「AutoJack: How a single page can RCE the host running your AI agent」と題した記事を公開した。この記事では、AIブラウジングエージェントが悪意あるWebページを1枚レンダリングするだけで、ホストマシン上でRCE(リモートコード実行)が成立する新型エクスプロイト「AutoJack」について詳しく解説されている。
「ページを閲覧させるだけ」でホストが乗っ取られる
AIエージェントにURLを渡して「このページを要約して」と頼む。それだけで攻撃者がホストマシン上で任意のコマンドを実行できる──AutoJackはそういうエクスプロイトだ。
MicrosoftのDefender Security Research Teamは、AutoGen Studio(Microsoftが開発するマルチエージェントフレームワークAutoGenのプロトタイピングUI)のMCP(Model Context Protocol) WebSocket実装に、3つの独立した脆弱性が連鎖するエクスプロイトチェーンを発見した。MCPとは、AIアシスタントが外部ツールやサービスと標準化された方法でやり取りするためのプロトコルで、エージェントフレームワークへの採用が急速に進んでいる。
なお、今回の脆弱性はMSRCへの報告後、アップストリームのmainブランチ(commit b047730)で修正済みだ。問題のMCP WebSocket機能はPyPIリリースには含まれておらず、pip install autogenstudioでインストールしたユーザーは本エクスプロイトには影響を受けない。 ただし、Microsoftが記事を公開した理由は「同様のパターンが他のエージェントフレームワークにも存在しうる」という点にある。
3つの脆弱性が連鎖する仕組み

Figure 1. エンドツーエンドのエクスプロイトチェーン。ローカルのブラウジングエージェントが攻撃者のページをレンダリングし、そのページがWebSocket経由でAutoGen StudioのMCPコントロールプレーンに接続、攻撃者が指定したコマンドが開発者アカウントで実行される。
Issue 1:Originのアローリストをエージェント自身が突破する(CWE-1385)
AutoGen StudioのMCP WebSocketは、http://127.0.0.1とhttp://localhostからの接続のみを受け付けるよう実装されていた。
allowed_origins = ["http://127.0.0.1", "http://localhost"]
これは人間がブラウザでevil.comを開くケースには有効だ。ブラウザはOriginヘッダにhttps://evil.comをセットするため、チェックに引っかかる。
しかし同一マシン上で動くエージェントには無力だ。 MultimodalWebSurferやfetch_webpage_toolなど、AutoGenのブラウジングツールはヘッドレスブラウザとして動作するローカルプロセスだ。そのエージェントがevil.comを訪問してJavaScriptを実行すると、発行されるWebSocket接続のOriginはlocalhostを名乗ることになり、アローリストを通過する。
Issue 2:認証ミドルウェアがMCPパスを意図的にスキップしていた(CWE-306)
AutoGen Studioは複数の認証モード(none, github, msal, firebase)をサポートするが、認証ミドルウェアには以下の記述があった。
# これらのパスは認証を除外。独自にチェックする想定
if request.url.path.startswith("/api/ws") or request.url.path.startswith("/api/mcp"):
return await call_next(request)
「WebSocketハンドシェイクはASGIミドルウェアでは適切にゲートできないため、WebSocketハンドラ側で認証する」という設計意図だったが、MCPのWebSocketハンドラはその認証を実装していなかった。結果として、下表の通り認証モードにかかわらず/api/mcp/ws/*は無認証でアクセス可能だった。
| 認証設定 | REST API保護 | /api/mcp/ws/*保護 |
|---|---|---|
| none | No | No |
| github | Yes | No |
| msal | Yes | No |
| firebase | Yes | No |
config.yamlで認証を有効化してもこの穴は塞がらない。
Issue 3:URLパラメータがそのままシェルコマンドになる(CWE-78)
MCP WebSocketのエンドポイントはserver_paramsというクエリパラメータを受け取り、Base64デコード→JSONパースしてStdioServerParamsに展開、そのまま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)
commandとargsに何を渡してもよく、アローリストは存在しない。calc.exeでもpowershell.exe -enc ...でもbash -c '...'でも受け付ける。ペイロードの最小構成は以下だ。
{
"type": "StdioServerParams",
"command": "calc.exe",
"args": [],
"env": { "pwned": "true" }
}
現実的な攻撃シナリオ
Microsoftのチームはエンドツーエンドの検証として2つのコンポーネントを用意した。
malicious_web_server.py:<script>タグで上記WebSocketに接続し、calc.exeを実行するBase64ペイロードを送信するだけのWebページweb_summarizer_app.py: FlaskのUIからURLを受け取り、MultimodalWebSurferエージェントに「このURLを要約して」と渡すWebアプリ
攻撃の流れはシンプルだ。ユーザーが攻撃者の仕掛けたURLをエージェントに渡す(直接指定、プロンプトインジェクション、URLフィールド経由など方法は問わない)→エージェントがそのページをレンダリング→ページ内JavaScriptがws://localhost:8081/api/mcp/ws/<id>?server_params=<base64>に接続→AutoGen Studioが開発者アカウントでコマンドを実行する。ユーザーの追加操作は不要だ。
本質的な教訓
Microsoftはこのエクスプロイトを「AutoJack」と命名した。ブラウジングエージェントを「乗っ取り(carjack)」、confused deputy(混乱した代理人)*として利用し、localhostの信頼境界を越えさせるという意味だ。
*confused deputy問題とは、権限を持つプログラム(deputy)が、権限のない第三者に悪用されて意図しない操作を実行させられるセキュリティ上のパターンを指す。CWEでも独立した分類(CWE-441)として定義されている。
記事が強調するのは次の1点だ。エージェントが外部Webを閲覧でき、かつ特権的なローカルサービスと通信できる環境では、localhostはもはや信頼境界として機能しない。 今回はAutoGen Studioが対象だったが、同様のMCP WebSocket実装を持つフレームワーク全般に同じパターンが潜在しうる。
開発者・セキュリティ担当者向けの対策として、記事はWebSocketエンドポイントへのToken/セッションベース認証の実装、MCP接続に対するコマンドアローリストの導入、エージェントのブラウジング権限と特権サービスへのアクセス権限の分離などを挙げている。
詳細はAutoJack: How a single page can RCE the host running your AI agentを参照していただきたい。




