All posts
Supply Chain Compromise

LiteLLM Virtual Key Walks Out With the Keyring

CVE-2026-35029 and CVE-2026-59823 let any LiteLLM virtual-key holder reach /config/update or exfiltrate upstream provider keys via SSRF

Securityv0 Intelligence Team OWASP: ASI06 sv0 finding: nhi_compromise
litellm ai-gateway nhi-compromise cve-2026-35029 cve-2026-59823 asi06

The Incident

On 2026-10-13, Check Point Research published When LLM Gateways Go Wrong: Findings from LiteLLM, synthesizing two patched LiteLLM Proxy flaws. CVE-2026-35029 (CVSS 3.1 8.8, CVSS 4.0 8.7, missing authorization) was discovered by SEC Consult’s Timo Müller on 2026-02-24, disclosed as GHSA-53mr-6c8q-9789 on 2026-04-03, published on NVD 2026-04-06, and fixed in litellm v1.83.0. The flaw lets any authenticated caller — including a low-privilege internal_user holding a budget-capped virtual key — reach /config/update, which the proxy never gated behind the proxy_admin role. From there a caller can register custom pass-through handlers that import attacker-controlled Python modules for remote code execution on the gateway host, set UI_LOGO_PATH to any filesystem path and retrieve the file through /get_image for arbitrary file read, or overwrite the UI_USERNAME and UI_PASSWORD environment variables to seize the admin UI.

CVE-2026-59823 (CVSS 4.0 5.3, authenticated SSRF) affects litellm >=1.34.0, <1.83.9 and ships fixed in v1.83.9. The proxy’s is_request_body_safe scanner inspects top-level api_base and base_url, but a caller can nest api_base inside user_config in a /chat/completions body — the router consumes the nested value and issues an outbound request to the attacker-chosen host with the gateway’s default headers attached, which carry the stored upstream provider API keys. Zenity Labs honeypot telemetry recorded about 3,900 requests from 73 IPs against LiteLLM admin routes between February and June 2026, roughly 1,000 of them against /config/update; the first /config/update probes landed 2026-04-07, one day after the GHSA, and file-read payloads matching the CVE-2026-35029 chain appeared between May 5 and May 12, 2026. MITRE ATT&CK coverage: T1068 Exploitation for Privilege Escalation, T1552.001 Credentials In Files, T1528 Steal Application Access Token, T1090 Proxy.

The Authority Path That Failed

LiteLLM Proxy is a non-human-identity concentrator: one authentication boundary — a bearer-token check against a per-caller virtual key — in front of every upstream provider API key an organization has issued to its OpenAI, Anthropic, and other LLM accounts. Two independent defects let a holder of the lowest-privilege virtual key walk past that boundary into the keyring. The scope internal_user virtual keys held was budgeted, rate-limited calls to /chat/completions and the model endpoints the operator permitted. The scope those same keys exercised under CVE-2026-35029 was full proxy configuration authority: the /config/update handler dispatched after bearer-token authentication but never checked the caller’s role, so any valid virtual key could rewrite proxy configuration, overwrite admin credentials, and register pass-through handlers that execute arbitrary Python inside the gateway process. The trust anchor that failed was a single missing role decorator; the v1.83.0 patch added the proxy_admin requirement in one place.

The second defect sits one layer deeper. CVE-2026-59823 is not an authorization gap but a parsing/enforcement boundary mismatch — the proxy’s is_request_body_safe scanner inspected top-level api_base and base_url in request bodies, but the proxy’s router still consumed the same fields when they appeared nested under user_config. One parser accepted a value the enforcement parser never saw, so a valid virtual key submitting a chat-completions request can redirect the proxy’s outbound call to a host it controls, taking the gateway’s default headers — the stored upstream provider API keys — along for the ride. In both CVEs the exercised scope ends at the same place: theft of the non-human identities the gateway holds for every operator that uses it.

SecurityV0 Perspective

This fits nhi_compromise. The pattern SV0 flags is a single authentication boundary sitting in front of an NHI concentrator — a service that collects and brokers machine identities on behalf of many callers — with no visibility inside into which per-caller identity holds which scope against which internal routes. The LiteLLM evidence pack SV0 would produce names every virtual key the proxy has issued, each key’s user_role (operator-intended internal_user or proxy_admin), the routes each role actually reached in the last 30 days of access logs, and the inventory of upstream provider API keys stored in environment variables or the proxy’s secret store with their last-rotated timestamps and the egress hosts they appear in traffic to.

The pre-exfiltration question the pack answers is “which of our virtual keys can reach /config/update, /get_image, or route an outbound call to an operator-unapproved host?” — the gap between held and exercised scope would have surfaced the missing role check on a static route-table read before April 2026. The post-exfiltration forensic question is “which outbound provider API calls between 2026-04-07 and the upgrade to v1.83.9 went to a host that was not an approved provider endpoint, and which virtual keys issued the chat-completions bodies that redirected them?” — the proxy’s own access logs plus egress telemetry answer it without a vendor’s cooperation.

What To Do

  • Upgrade to LiteLLM v1.83.9 or later. v1.83.0 added the proxy_admin role check on /config/update (fixing CVE-2026-35029) and v1.83.9 added nested-field scanning in is_request_body_safe (fixing CVE-2026-59823). Earlier releases are vulnerable to one or both; the single safe target is v1.83.9 or newer. Pin the version in the Helm chart or compose file rather than tracking latest.
  • Rotate every upstream provider API key stored in the proxy, and every LiteLLM virtual key issued since 2026-04-07. Zenity Labs puts in-the-wild /config/update probes beginning one day after the GHSA, with file-read payloads active by mid-May. Any key that lived in the proxy’s env vars, under a UI_LOGO_PATH-reachable file, or in default outbound headers across that window is suspect. Mint replacement provider keys, cut the old virtual keys at the proxy, and record the rotation in your NHI inventory.
  • Enforce the proxy_admin role at an upstream reverse proxy, not only inside LiteLLM. Put an authenticating gateway in front (Nginx with mTLS, Envoy with an external authz filter, or a WAF rule set) that denies every request path under /config/*, /get_image, and the admin UI unless the caller presents a credential the gateway itself maps to the proxy_admin role. A single missing decorator inside LiteLLM should not be the only control between a budgeted virtual key and the keyring.
  • Restrict LiteLLM’s outbound egress to the exact provider hostnames you use. CVE-2026-59823 exfiltrates provider keys by sending them to an attacker-chosen host; a per-pod or per-VM egress allowlist that only permits DNS resolution and TLS connections to api.openai.com, api.anthropic.com, and your other named provider endpoints removes the SSRF’s exfiltration channel even when a parser mismatch is live. Log every egress denial with the source virtual key and request ID.
  • Alert on changes to UI_LOGO_PATH, UI_USERNAME, UI_PASSWORD, and pass-through handler registrations in the proxy configuration. Those four handles are what CVE-2026-35029 pulls to reach file read, admin takeover, and RCE. The proxy’s own config database or audit log is the right source; alert on any write to those fields that is not accompanied by a scheduled operator change ticket.

Sources