Unauthenticated SSRF and worker/model spoofing via the controller /register_worker endpoint
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 39.5k
- Forks
- 4.8k
- PR merge metrics
- No merged PRs in 30d
Description
### 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`:
```python
@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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in fastchat/serve/controller.py at register_worker, get_worker_status, receive_heart_beat, and the worker proxy paths; compare the authentication approach in openai_api_server, where check_api_key is mentioned. Done means unauthenticated worker-management requests cannot trigger fetches or registrations, and worker_name is restricted to expected addresses without exposing the controller to untrusted networks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api, backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100