Skip to content

Unauthenticated SSRF and worker/model spoofing via the controller /register_worker endpoint #3886

Description

@geo-chen

Summary

The FastChat controller exposes a /register_worker endpoint with no authentication. The request body field worker_name is an attacker-controlled address that the controller immediately fetches (requests.post(worker_name + "/worker_get_status")) and then stores as a serving worker. This gives an unauthenticated client that can reach the controller two primitives: server-side request forgery into the cluster's private network, and worker/model spoofing, where the attacker registers their own address under a model name so the controller proxies every user generation request (prompts and images) to the attacker and streams the attacker's response back to clients. Confirmed against the real booted controller: /register_worker fetched an internal listener and registered a spoofed model.

Details

fastchat/serve/controller.py:

@app.post("/register_worker")            # ~line 288: no auth dependency
def register_worker(request: Request): ...
# register_worker (~line 75) -> get_worker_status (~line 106):
r = requests.post(worker_name + "/worker_get_status", timeout=5)   # SSRF: worker_name from the request body

The controller FastAPI app has no authentication on any endpoint (unlike openai_api_server, which has check_api_key). data["worker_name"] is a fully attacker-controlled URL. Once registered, the controller routes user traffic to it: worker_api_generate_stream (~lines 266 to 280) does requests.post(worker_addr + "/worker_generate_stream", json=params), forwarding the user's full prompt (and images) to the registered address, and /get_worker_address / /list_models hand the attacker address and model name to clients.

The default bind is localhost (~line 355), but FastChat's documented multi-node deployment runs the controller with --host 0.0.0.0 behind the 0.0.0.0-bound OpenAI API server and gradio frontends, so the controller is reachable on the network in real deployments.

PoC

Impact

An unauthenticated client that can reach the controller can (1) make the controller issue requests to arbitrary internal addresses (SSRF / internal port-probing across the worker mesh), and (2) register a malicious worker under a victim model name so the controller proxies every user generation request to the attacker, exfiltrating user prompts/images and poisoning the responses returned to all clients of that model. In the documented network-exposed multi-node deployment this is a high-impact unauthenticated compromise of the serving cluster.

Remediation

Require authentication on the controller's worker-management endpoints (/register_worker, /receive_heart_beat, etc.) with a shared secret known only to legitimate workers, and validate/allowlist worker_name against expected worker addresses (reject internal/loopback/metadata targets and arbitrary hosts). Do not fetch a client-supplied address before authenticating the registrant. Document that the controller must not be exposed to untrusted networks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions