From d5efca5baf93f3753c61e53a01a065561f7235ea Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 5 Aug 2026 16:07:04 -0700 Subject: [PATCH] fix(health): drop a stored-credential reference along with the credentials it names A connection test that redirects the destination already leaves the configured credentials behind. It kept litellm_credential_name, which names the same stored secrets and is resolved further down the call, so the reference is now dropped with them. A request that sets no connection fields of its own is unaffected, which is how the Admin UI tests a configured model. (cherry picked from commit 298fb8ce56099774f310594c9970cc24a9b8f900) --- .../health_endpoints/_health_endpoints.py | 11 ++++++++++- .../health_endpoints/test_health_endpoints.py | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/health_endpoints/_health_endpoints.py b/litellm/proxy/health_endpoints/_health_endpoints.py index 51d9d34c956..d9bcd8c1a65 100644 --- a/litellm/proxy/health_endpoints/_health_endpoints.py +++ b/litellm/proxy/health_endpoints/_health_endpoints.py @@ -98,7 +98,11 @@ def _reject_os_environ_references(params: dict) -> None: _CONFIG_CONNECTION_FIELDS: Final[frozenset[str]] = frozenset( - (*_ADMIN_CONFIG_FIELDS_TO_CLEAR_ON_BASE_OVERRIDE, *clientside_credential_keys) + ( + *_ADMIN_CONFIG_FIELDS_TO_CLEAR_ON_BASE_OVERRIDE, + *clientside_credential_keys, + "litellm_credential_name", + ) ) @@ -115,6 +119,11 @@ def _config_base_for_health_check( still comes from the configuration, which is what lets a request name a configured model and test it as configured. + ``litellm_credential_name`` is dropped alongside the literal credential + fields: it names a stored credential that ``load_credentials_from_list`` + resolves into the same secrets further down the call, so leaving it in place + would reintroduce them by reference. + ``general_settings.allow_client_side_credentials`` is the existing proxy-wide opt-in for callers supplying their own connection parameters. Where an admin has enabled it, a request may pair its own endpoint with the configured diff --git a/tests/test_litellm/proxy/health_endpoints/test_health_endpoints.py b/tests/test_litellm/proxy/health_endpoints/test_health_endpoints.py index cef2e643194..f74aafd9df1 100644 --- a/tests/test_litellm/proxy/health_endpoints/test_health_endpoints.py +++ b/tests/test_litellm/proxy/health_endpoints/test_health_endpoints.py @@ -2438,3 +2438,22 @@ class TestConfigBaseForHealthCheck: allow_client_side_credentials=True, ) assert base["api_key"] == "sk-configured" + + def test_stored_credential_reference_is_dropped_with_the_credentials(self): + """A stored-credential name resolves to the same secrets downstream, so a + request that redirects the destination must not keep it either.""" + config = {**self.CONFIG, "litellm_credential_name": "OpenAI-prod"} + base = self._base(config, {"api_base": "https://caller.example/v1"}) + assert "litellm_credential_name" not in base + assert "api_key" not in base + + def test_stored_credential_reference_kept_when_request_sets_no_connection(self): + """The Admin UI tests a configured model by naming it plus its stored + credential and nothing else; that keeps working.""" + config = {**self.CONFIG, "litellm_credential_name": "OpenAI-prod"} + base = self._base( + config, + {"model": "openai/gpt-4o", "litellm_credential_name": "OpenAI-prod", "custom_llm_provider": "openai"}, + ) + assert base["litellm_credential_name"] == "OpenAI-prod" + assert base["api_key"] == "sk-configured"