From 27863e35b52d4c828036ca9ce2a18c18faf945cc Mon Sep 17 00:00:00 2001 From: Nico Duldhardt Date: Sat, 14 Feb 2026 18:11:43 +0100 Subject: [PATCH] fix(security): strip x-litellm-api-key from forwarded headers to upstream providers Prevent x-litellm-api-key (LiteLLM's virtual key) from being leaked to upstream providers when _forward_headers=True is used in passthrough endpoints. --- litellm/passthrough/utils.py | 1 + ...test_passthrough_endpoints_common_utils.py | 42 ++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/litellm/passthrough/utils.py b/litellm/passthrough/utils.py index fbbf9cd2581..c8ef25881dd 100644 --- a/litellm/passthrough/utils.py +++ b/litellm/passthrough/utils.py @@ -39,6 +39,7 @@ class BasePassthroughUtils: # Header We Should NOT forward request_headers.pop("content-length", None) request_headers.pop("host", None) + request_headers.pop("x-litellm-api-key", None) # Combine request headers with custom headers headers = {**request_headers, **headers} diff --git a/tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py b/tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py index 97ef05100de..b7e7359e9ff 100644 --- a/tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py +++ b/tests/test_litellm/proxy/pass_through_endpoints/test_passthrough_endpoints_common_utils.py @@ -10,7 +10,7 @@ import pytest from fastapi import Request, Response from fastapi.testclient import TestClient -from litellm.passthrough.utils import CommonUtils +from litellm.passthrough.utils import BasePassthroughUtils, CommonUtils sys.path.insert( 0, os.path.abspath("../../../..") @@ -95,4 +95,42 @@ def test_encode_bedrock_runtime_modelid_arn_edge_cases(): endpoint = "model/arn:aws:bedrock:us-east-1:123456789012:application-inference-profile/test-profile.v1/invoke" expected = "model/arn:aws:bedrock:us-east-1:123456789012:application-inference-profile%2Ftest-profile.v1/invoke" result = CommonUtils.encode_bedrock_runtime_modelid_arn(endpoint) - assert result == expected \ No newline at end of file + assert result == expected + + +def test_forward_headers_strips_litellm_api_key(): + """x-litellm-api-key should not be forwarded to upstream providers.""" + request_headers = { + "x-litellm-api-key": "sk-litellm-secret-key", + "content-type": "application/json", + "x-api-key": "sk-ant-api-key", + } + + result = BasePassthroughUtils.forward_headers_from_request( + request_headers=request_headers.copy(), + headers={}, + forward_headers=True, + ) + + assert "x-litellm-api-key" not in result + assert result.get("content-type") == "application/json" + assert result.get("x-api-key") == "sk-ant-api-key" + + +def test_forward_headers_strips_host_and_content_length(): + """host and content-length should not be forwarded.""" + request_headers = { + "host": "api.anthropic.com", + "content-length": "1234", + "content-type": "application/json", + } + + result = BasePassthroughUtils.forward_headers_from_request( + request_headers=request_headers.copy(), + headers={}, + forward_headers=True, + ) + + assert "host" not in result + assert "content-length" not in result + assert result.get("content-type") == "application/json" \ No newline at end of file