← Back to Feed CACHED · 2026-10-14 13:33:09 · CACHE_KEY CVE-2026-59823
CVE-2026-59823 · CWE-918 · Disclosed 2026-09-16

LiteLLM Proxy SSRF via user_config parameter enables LLM provider API key theft

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

Like handing your building's master key ring to every tenant and hoping none of them makes copies

CVE-2026-59823 is a server-side request forgery in LiteLLM Proxy (all versions before 1.83.9) that lets any authenticated user — anyone holding a valid virtual API key — redirect the gateway's outbound LLM requests to an attacker-controlled server. The trick is straightforward: LiteLLM's is_request_body_safe function blocks top-level api_base and base_url parameters to prevent endpoint hijacking, but it never descends into the nested user_config object. By embedding a malicious api_base inside user_config in a /chat/completions call, the attacker causes LiteLLM to instantiate a brand-new litellm.Router pointing at their own server. Every subsequent request — along with the production API keys for OpenAI, Anthropic, Google, or Azure OpenAI — gets delivered straight to the attacker instead of the real provider. The user_config code path is reachable regardless of the configurable_clientside_auth_params setting; it's a separate, unguarded branch.

No NVD or vendor CVSS baseline exists for this CVE. The GitHub Security Advisory (GHSA-hx8v-g79f-8w5f) assigns CVSS 4.0 score 5.3 MEDIUM with VC:L/SC:L, and the GitLab advisory carries a CVSS 3.1 vector scoring ~5.0 with C:L. Both ratings treat this as a generic information-disclosure SSRF — the kind that lets you probe internal metadata endpoints. That framing is wrong. This is a credential-theft SSRF that silently exfiltrates every LLM provider API key the gateway holds. LiteLLM with 92M+ monthly PyPI downloads functions as the de facto credential aggregator for enterprise AI stacks. Stealing its keys means financial exposure (API spend in the tens of thousands), prompt data interception, and potential downstream access to any data the LLM providers can reach. The MEDIUM label fundamentally mischaracterizes the blast radius.

"Authenticated SSRF steals LLM provider API keys through a nested config bypass in the AI gateway."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Obtain a valid virtual key

The attacker needs a valid LiteLLM virtual API key to authenticate to the proxy. In enterprise deployments, virtual keys are distributed to development teams, CI pipelines, Jupyter notebooks, and application tiers. A compromised developer laptop, leaked .env file, exposed notebook, or insider threat provides the key. The key only needs the lowest privilege level — any authenticated caller will do.
Conditions required:
  • Valid LiteLLM virtual API key
  • Network access to the LiteLLM Proxy endpoint (typically internal, but ~3K instances on Shodan)
Where this breaks in practice:
  • Enterprise proxies are typically behind VPN or internal network
  • Key rotation policies may limit key lifespan
  • Audit logs may capture key usage patterns
Detection/coverage: LiteLLM access logs show authenticated requests; anomalous source IPs or sudden usage spikes from unfamiliar keys are detectable with SIEM correlation.
STEP 02

Craft malicious user_config payload

The attacker constructs a JSON request body for /chat/completions with a user_config object containing a model_list entry where api_base points to an attacker-controlled HTTPS endpoint. This is trivial — the vulnerable code path is router_config = data.pop('user_config'); user_router = litellm.Router(**router_config) with zero validation on the nested object. No special tooling required; a single curl command suffices.
Conditions required:
  • Knowledge of the user_config parameter structure (documented in Check Point Research writeup and LiteLLM docs)
Where this breaks in practice:
  • None — the payload structure is publicly documented and trivially reproducible
Detection/coverage: WAF rules inspecting JSON body depth for nested api_base or user_config keys could flag this. Most default WAF rulesets do not inspect nested JSON parameters.
STEP 03

Bypass is_request_body_safe validation

The request hits LiteLLM's is_request_body_safe function, which checks only for top-level api_base and base_url keys. The user_config object passes through untouched because it's a separate, unguarded code path — completely independent of configurable_clientside_auth_params. The request is accepted as a normal authenticated API call.
Conditions required:
  • LiteLLM Proxy version < 1.83.9
Where this breaks in practice:
  • If the proxy has been updated to 1.83.9+, the fix blocks this path
  • The fix shipped April 17, 2026 — ~6 months of patch window already elapsed
Detection/coverage: Application-level logging may record user_config in request payloads. A custom detection rule matching on this key name in POST bodies to /chat/completions is straightforward to implement.
STEP 04

LiteLLM instantiates attacker-controlled router

LiteLLM's request handler creates a new litellm.Router object using the attacker's configuration verbatim via litellm.Router(**router_config). This router is configured with the attacker's api_base as the upstream endpoint. The proxy then routes the completion request — including all default headers containing the production LLM provider API keys — to the attacker's server instead of the legitimate provider.
Conditions required:
  • The user_config code path is reachable (default behavior, no special configuration required)
Where this breaks in practice:
  • None — this is core proxy routing functionality being abused as designed
Detection/coverage: Network monitoring for outbound connections from the LiteLLM process to unexpected IP addresses or domains. Egress firewall rules allowing only known LLM provider endpoints (api.openai.com, api.anthropic.com, etc.) would block the redirect.
STEP 05

API keys and prompt data exfiltrated

The attacker's server receives the full HTTP request, including provider API keys (OpenAI, Anthropic, Google, Azure OpenAI) in authorization headers and the complete prompt payload in the request body. The attacker now possesses production credentials for the organization's LLM providers and can use them independently, replay intercepted prompts, or sell the keys. A sophisticated attacker can even proxy the request onward to the real provider to maintain stealth — the victim sees normal responses while their keys are silently copied.
Conditions required:
  • Attacker has an HTTPS listener ready to receive redirected requests
Where this breaks in practice:
  • Transparent proxying by the attacker makes detection harder but is not required for key theft
Detection/coverage: Provider-side API key usage anomalies (new source IPs, geographic anomalies, sudden spend spikes) may be the first external signal. LLM provider audit logs showing usage from unknown infrastructure are the canary.
03 · Compensating Control

1
HIGH 7.1→IGNORE 0.0
SEVERITY REDUCED
Upgrade LiteLLM to ≥ 1.83.9 — The definitive fix. Commit 47214be adds validation of the user_config parameter to reject nested api_base smuggling. The fix shipped 2026-04-17 — nearly 6 months ago. Per the noisgate HIGH remediation SLA, deploy within 180 days. Given the fix has been available since April, prioritize production gateways this sprint and dev/staging within 30 days. Run pip install --upgrade 'litellm>=1.83.9' and restart the proxy process.
2
HIGH 7.1→LOW 2.5
SEVERITY REDUCED
Block user_config in request bodies at WAF or reverse proxy — Configure your WAF or API gateway (Cloudflare, AWS WAF, Kong, nginx+Lua, or Envoy) to reject any POST to /chat/completions whose JSON body contains the key user_config. This breaks the attack path at step 2 without requiring a LiteLLM upgrade. Per the noisgate HIGH mitigation SLA, deploy within 30 days — or immediately if you cannot upgrade quickly. Example nginx rule: deny requests where $request_body matches "user_config".
3
HIGH 7.1→LOW 3.0
SEVERITY REDUCED
Restrict LiteLLM egress to known LLM provider endpoints only — Configure egress firewall rules (network firewall, security group, or proxy) to allow the LiteLLM process to connect outbound only to known LLM provider domains: api.openai.com, api.anthropic.com, generativelanguage.googleapis.com, *.openai.azure.com, etc. This prevents the SSRF redirect from reaching an attacker-controlled server even if the request is crafted successfully. Per the noisgate HIGH mitigation SLA, deploy within 30 days.
4
HIGH 7.1→HIGH 7.1
Rotate all LLM provider API keys immediately — If your LiteLLM instance has been running a vulnerable version (< 1.83.9) in production, assume keys may already be compromised. Rotate API keys for all configured providers (OpenAI, Anthropic, Google, Azure OpenAI) and audit provider-side usage logs for anomalous activity — new source IPs, geographic anomalies, unexpected spend spikes. Per the noisgate HIGH mitigation SLA, initiate within 30 days; if you see suspicious provider-side activity, rotate within hours.
5
HIGH 7.1→MEDIUM 5.0
SEVERITY REDUCED
Remove internet exposure and enforce network-layer auth — Ensure LiteLLM Proxy is not directly exposed to the internet. Place it behind VPN, ZTNA, or internal-only load balancers with mTLS. This eliminates the ~3K Shodan-exposed attack surface and limits exploitation to authenticated insiders or post-compromise lateral movement only. Per the noisgate HIGH mitigation SLA, deploy within 30 days.
6
HIGH 7.1→MEDIUM 5.5
SEVERITY REDUCED
Implement virtual key least-privilege, scoping, and rotation — Minimize the number of active virtual keys, scope each key to specific models and providers, enforce short TTLs (< 90 days), and audit key distribution. Remove keys from CI logs, Jupyter notebooks, .env files in version control, and Slack messages. This reduces the probability of an attacker obtaining a valid key (PR:L friction). Per the noisgate HIGH mitigation SLA, begin within 30 days.
What doesn't work
  • Network segmentation alone does not help if the attacker is an authenticated internal user (insider threat) or holds a leaked virtual key. The attack originates from a legitimate authenticated session within the trusted network boundary.
  • Rate limiting does not help — the attack requires a single HTTP request to exfiltrate all provider keys. There is no brute-force, scanning, or volume component to throttle.
  • LiteLLM's built-in is_request_body_safe function (pre-1.83.9) is the exact control that was bypassed — it only inspects top-level keys. Do not rely on it as a compensating control without the patch.
  • TLS inspection of outbound traffic can detect the redirect to an unexpected destination but cannot prevent the initial key leakage — by the time TLS inspection sees the outbound connection, the request carrying the API key has already been constructed and is in flight to the attacker's endpoint.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo confirmed exploitation of CVE-2026-59823 specifically. However, sibling CVE-2026-59822 (MCP auth bypass, CVSS 8.2) is KEV-listed and actively exploited per CISA. The Cloud Security Alliance documented active exploitation via MCP injection. LiteLLM was also the target of a supply chain compromise (PyPI packages v1.82.7/v1.82.8 backdoored per Snyk). Attackers are demonstrably targeting this software.
Proof-of-concept availabilityNo standalone PoC repo found on GitHub or pocindex.io for this specific CVE. However, the Check Point Research writeup contains the complete vulnerable code path (data.pop('user_config') → litellm.Router(router_config)) and enough detail to reproduce with a single curl command. Exploitation is trivial** once authenticated — no tooling needed beyond curl or any HTTP client.
EPSS0.00439 (0.44% probability of exploitation in next 30 days), 35.7th percentile. Low signal, but EPSS historically underweights authenticated vulns in niche software. The active threat context around LiteLLM (KEV sibling, supply chain compromise) overrides the EPSS baseline.
KEV statusNot listed. Related CVE-2026-59822 (LiteLLM MCP auth bypass) IS on KEV. CVE-2026-59823 could be added if exploitation is confirmed, given the demonstrated attacker interest in LiteLLM infrastructure.
CVSS vectorGHSA assigns CVSS 4.0: CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N (5.3). GitLab advisory: CVSS 3.1: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:N/A:N (~5.0). The S:C (scope changed) correctly identifies cross-component impact, but C:L undervalues the credential-theft outcome — stealing production API keys is not 'Low' confidentiality impact.
Affected versionsAll LiteLLM versions < 1.83.9. Vulnerability confirmed on version 1.77.7 by Check Point Research. The user_config code path exists in all proxy versions that support the clientside credentials feature.
Fixed version1.83.9 (released 2026-04-17). Fix commit: 47214be. No distro backports — LiteLLM is Python-only via PyPI (pip install litellm).
Exposure (Shodan/Wiz)Wiz Research found 3,074 LiteLLM gateways on Shodan (Feb 2026); 294 (9.6%) accepted the default admin key sk-1234. August 2026 rescan showed 85K+ instances (most assessed as honeypots/test systems). The Hacker News covered the default-key exposure.
Disclosure timelineFix shipped 2026-04-17 in v1.83.9. Public advisory published 2026-09-16 — fix preceded disclosure by ~5 months. Coordinated disclosure by Check Point Research covering four LiteLLM vulnerabilities.
ResearcherReported by brettgus (Check Point Research). Part of a coordinated disclosure alongside CVE-2026-35029 (config update authz bypass → RCE) and two other findings.

Sources.

  1. Check Point Research — When LLM Gateways Go Wrong: Findings from LiteLLM
  2. GitHub Security Advisory GHSA-hx8v-g79f-8w5f
  3. Wiz Research — Breaking LiteLLM: From Auth Bypass to Cloud Compromise
  4. GitLab Advisory — CVE-2026-59823
  5. OSV — GHSA-hx8v-g79f-8w5f
  6. The Hacker News — Nearly 1 in 10 Exposed LiteLLM Gateways Accepted Default Key
  7. LiteLLM Clientside Auth Documentation
  8. Check Point Blog — High Risk Vulnerabilities in LiteLLM
05 · The Call

Final Verdict
= UNCHANGED to HIGH (7.1/10)

Why this verdict

  • Credential-theft SSRF, not port-scan SSRF: The advisory-assigned C:L rating treats this as a generic information-disclosure SSRF. In reality, the redirected requests carry production API keys for OpenAI, Anthropic, Google, and Azure OpenAI in authorization headers, plus full prompt payloads in the request body. Stealing a fleet of LLM provider keys is a HIGH-impact credential compromise — the equivalent of exfiltrating a secrets vault, not reading a cloud metadata endpoint. The real confidentiality impact is HIGH, not LOW.
  • Authentication is real friction but bounded: PR:L requires a valid virtual key. In enterprise deployments, virtual keys are distributed broadly to dev teams, CI/CD pipelines, notebooks, and application tiers — often hundreds of active keys across an org. A single compromised .env file, leaked CI log, or insider provides access. This narrows the attacker population but does not eliminate it; we estimate 10–30% of enterprise LiteLLM deployments have keys accessible to non-security-vetted principals.
  • Active threat actor interest in LiteLLM (threat multiplier): Sibling CVE-2026-59822 (MCP auth bypass) is KEV-listed with confirmed in-the-wild exploitation. LiteLLM was also the target of a PyPI supply chain compromise (v1.82.7/v1.82.8 backdoored). Attackers are actively targeting this software family. A documented SSRF with trivial post-auth exploitation *will* be discovered and chained by groups already operating inside LiteLLM environments.
  • Role multiplier: LiteLLM is deployed as an AI gateway and credential aggregator — its primary function is holding API keys for multiple LLM providers in a single location. (a) *Low-value role* (dev sandbox/hobby): impact is one developer's test keys — LOW. (b) *Typical role* (team AI gateway): impact is team-level API keys, moderate financial and data exposure — MEDIUM. (c) *High-value role* (enterprise production AI gateway routing 500M+ tokens/month across 20+ teams per the Midas Engineering case study): blast radius is org-wide credential compromise — all provider keys stolen, all prompt data interceptable, financial exposure in tens of thousands of dollars per month. This high-value role represents ≥30% of production LiteLLM deployments — it is the product's canonical enterprise use case. The attack chain succeeds identically in this role with no additional prerequisites. Outcome is mass credential egress → verdict floor is HIGH.
  • Trivial exploitation post-auth: The attack requires a single HTTP request with a nested JSON parameter. No memory corruption, no race condition, no timing window, no special tooling. The Check Point writeup documents the exact 2-line code path. Time-to-exploit from key possession to credential exfiltration is measured in seconds.
  • Non-trivial internet exposure: 3,074 real instances found on Shodan by Wiz Research, with 9.6% accepting the default sk-1234 admin key. While most enterprise deployments are internal-only, the exposed surface is non-trivial and actively scanned by threat actors.

Why not higher?

CRITICAL would require either unauthenticated access or infrastructure-level blast radius (domain takeover, fleet compromise, supply-chain pivot). This CVE requires a valid virtual key (PR:L), and the stolen credentials are LLM provider API keys — not infrastructure credentials like domain admin tokens, PKI private keys, or hypervisor console access. The blast radius is bounded to AI service credential theft and prompt data exposure — significant financially and operationally, but not domain-scale or fleet-scale. LiteLLM is not canonically infrastructure-defining software (it is not AD, PKI, ESXi, a kernel-mode agent, or a network edge appliance), so the CRITICAL floor does not apply.

Why not lower?

MEDIUM would ignore the credential-theft nature of this SSRF and LiteLLM's role as a credential aggregator holding keys to the organization's entire AI spend. The advisory-assigned C:L is objectively wrong for an attack that exfiltrates production API keys carrying five- and six-figure annual billing exposure. The active targeting of LiteLLM by threat actors — a KEV-listed sibling CVE, a confirmed supply chain compromise — elevates the threat environment well beyond what the 35th-percentile EPSS suggests. The fix has been available for six months; any unpatched instance is an increasingly high-confidence target as awareness spreads.

06 · Verification

Crowdsourced verification payload.

Run this script on any host where LiteLLM is installed — typically the proxy server itself or any machine with the litellm Python package in its environment. No special privileges required; it performs a read-only version check. Invoke with: python3 check_cve_2026_59823.py

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
"""CVE-2026-59823: LiteLLM Proxy SSRF via user_config parameter.
Checks whether the installed litellm version is vulnerable.
Fixed in version 1.83.9.

Exit codes:
  1 = VULNERABLE
  0 = PATCHED
  2 = UNKNOWN (package not found or version unparseable)
"""
import sys

FIXED_VERSION = (1, 83, 9)

def parse_version(v):
    """Parse version string into comparable tuple, stripping pre-release tags."""
    parts = []
    for segment in v.split('.'):
        num_str = ''
        for ch in segment:
            if ch.isdigit():
                num_str += ch
            else:
                break
        parts.append(int(num_str) if num_str else 0)
    # Pad to 3 components
    while len(parts) < 3:
        parts.append(0)
    return tuple(parts[:3])

try:
    try:
        from importlib.metadata import version as pkg_version
    except ImportError:
        from importlib_metadata import version as pkg_version  # Python < 3.8

    installed_str = pkg_version('litellm')
    installed = parse_version(installed_str)

    if installed < FIXED_VERSION:
        print(f'VULNERABLE - litellm {installed_str} installed (fixed in 1.83.9)')
        print(f'  CVE-2026-59823: SSRF via user_config parameter')
        print(f'  Impact: LLM provider API key theft via crafted /chat/completions request')
        print(f'  Upgrade: pip install --upgrade "litellm>=1.83.9"')
        sys.exit(1)
    else:
        print(f'PATCHED - litellm {installed_str} installed (>= 1.83.9)')
        sys.exit(0)

except Exception as e:
    print(f'UNKNOWN - could not determine litellm version: {e}')
    print('  Ensure litellm is installed in this Python environment.')
    print('  Try: pip show litellm')
    sys.exit(2)