LiteLLM Proxy Privilege Escalation via `/user/update` (CVE-2026-47102)
by Fenix Qiao (13ph03nix) — Obsidian Security · 2026-07-05
- Severity
- High
- CVE
- CVE-2026-47102
- Category
- web
- Affected product
- LiteLLM (LLM API proxy / gateway)
- Affected versions
- < 1.83.10 (confirmed on 1.83.7; fixed in 1.83.10)
- Disclosed
- 2026-07-05
- Patch status
- patched
References
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-07 |
| Author / Researcher | Fenix Qiao (13ph03nix) — Obsidian Security |
| CVE / Advisory | CVE-2026-47102 |
| Category | web |
| Severity | High |
| CVSS Score | 8.8 (CVSS v3.1: AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| Status | PoC |
| Tags | litellm, privilege-escalation, broken-access-control, cwe-863, api-authorization, llm-proxy |
| Related | CVE-2026-47101 (chainable /key/generate wildcard-route vulnerability) |
Affected Target
| Field | Value |
|---|---|
| Software / System | LiteLLM (LLM API proxy / gateway) |
| Versions Affected | < 1.83.10 (confirmed on 1.83.7; fixed in 1.83.10) |
| Language / Platform | Python (FastAPI-based proxy) |
| Authentication Required | Yes (any low-privileged API key with route access to /user/update) |
| Network Access Required | Yes |
Summary
LiteLLM’s /user/update endpoint is meant to let a user update their own account attributes (name, email, metadata). The authorization check can_user_call_user_update() only verifies which user record the caller may modify (their own, or any if they are already proxy_admin) but does not restrict which fields a self-update may change. A low-privileged internal_user who has been granted (or otherwise obtains) API-key route access to /user/update can therefore include user_role in their own update request and set it to proxy_admin, instantly escalating to full administrative privileges over the LiteLLM proxy.
Vulnerability Details
Root Cause
internal_user_endpoints.py’s can_user_call_user_update() allows a self-update (user_api_key_dict.user_id == user_info.user_id) without validating the set of fields being modified:
| |
The fix (v1.83.10+) adds field-level authorization, restricting non-admin self-updates to an allow-list (metadata, display_name, email) and rejecting any request that attempts to modify user_role.
Attack Vector
- An administrator creates a low-privileged
internal_useraccount (POST /user/new). - The administrator grants that user (or a key belonging to them) route-level access to
/user/update— e.g. viaPOST /key/generatewithallowed_routes: ["/user/update"]— or the attacker obtains such a key by chaining CVE-2026-47101 (/key/generatewildcard route abuse). - Using that key, the attacker calls:
POST /user/update {"user_id": "<own-user-id>", "user_role": "proxy_admin"} - The endpoint accepts the self-update without checking that
user_roleis outside the caller’s permitted field set, and the user’s role is changed toproxy_admin. - The attacker (using their original, route-unrestricted API key, now tied to a
proxy_adminuser) calls admin-only endpoints such as/user/listor/user/deleteto confirm and abuse full administrative access.
Impact
Any user granted (directly or via a chained vulnerability) access to the /user/update route can escalate to full proxy_admin privileges over the LiteLLM proxy — gaining the ability to list, modify, and delete any user, manage API keys and spend limits, and access all administrative functionality of the proxy.
Environment / Lab Setup
Target: LiteLLM v1.83.7-stable (vulnerable) and v1.83.10-stable (fixed, for comparison), via docker-compose
Backing DB: PostgreSQL
Attacker: curl / bash, or the bundled demo.sh / exploit/exploit.py + exploit/payload.py
Proof of Concept
PoC Script
See
demo.sh,exploit/exploit.py,exploit/payload.py,config.yaml, anddocker-compose.ymlin this folder.
| |
demo.sh automates: creating an internal_user, granting that user a key scoped to /user/update, calling /user/update to set user_role: proxy_admin, and then verifying elevated access via /user/list. Running it against docker-compose --profile fixed up -d litellm-fixed (v1.83.10) shows the same request rejected with "Only proxy admins can modify user roles.", confirming the vulnerability and the fix.
Detection & Indicators of Compromise
POST /user/update {"user_id": "...", "user_role": "proxy_admin", ...}
Signs of compromise:
- Non-admin API keys successfully calling
/user/updatewith auser_rolefield in the request body. - Users whose
user_rolechanged toproxy_adminwithout a corresponding administrator-initiated action. - Unexpected calls to
/user/listor/user/deletefrom keys originally provisioned asinternal_user.
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade to LiteLLM ≥ 1.83.10, which adds field-level authorization to /user/update and blocks non-admin modification of user_role. |
| Interim mitigation | Restrict API key route grants to only the minimum necessary routes; avoid granting /user/update access to non-admin users; audit existing users/keys for unexpected proxy_admin role assignments; monitor /user/update calls that include user_role changes. |
References
Notes
Mirrored from https://github.com/learner202649/CVE-2026-47102-PoC on 2026-07-05. Chainable with CVE-2026-47101 (/key/generate wildcard-route authorization bypass) for privilege escalation starting from a key with no explicit route grants.
| |