From 5e8468c51c98eda3bc0283bf53d1b50cf0144bb0 Mon Sep 17 00:00:00 2001 From: Mrinal Chanshetty Date: Thu, 5 Nov 2026 15:39:40 -0800 Subject: [PATCH] fix(proxy): hide LDAP credentials in validation errors --- litellm/types/proxy/ldap_sync.py | 2 +- .../proxy/common_utils/test_ldap_directory.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/litellm/types/proxy/ldap_sync.py b/litellm/types/proxy/ldap_sync.py index 0b47e095d2a..73e2f0a168f 100644 --- a/litellm/types/proxy/ldap_sync.py +++ b/litellm/types/proxy/ldap_sync.py @@ -6,7 +6,7 @@ from typing_extensions import Self class LDAPSyncSettings(BaseModel): - model_config = ConfigDict(frozen=True, extra="forbid") + model_config = ConfigDict(frozen=True, extra="forbid", hide_input_in_errors=True) enabled: bool = False server_url: str = "" diff --git a/tests/unit/proxy/common_utils/test_ldap_directory.py b/tests/unit/proxy/common_utils/test_ldap_directory.py index 21542869738..3de67f00335 100644 --- a/tests/unit/proxy/common_utils/test_ldap_directory.py +++ b/tests/unit/proxy/common_utils/test_ldap_directory.py @@ -242,6 +242,22 @@ def test_invalid_configuration_is_rejected(updates: Mapping[str, object]): LDAPSyncSettings.model_validate({**SETTINGS.model_dump(), **updates}) +@pytest.mark.parametrize( + "updates,message", + [ + ({"bind_dn": "cn=admin", "start_tls": False}, "require TLS"), + ({}, "bind_dn and bind_password must be configured together"), + ], +) +def test_invalid_configuration_errors_do_not_expose_bind_password(updates: Mapping[str, object], message: str): + password: Final = "qa-secret-42" + with pytest.raises(ValidationError, match=message) as error: + LDAPSyncSettings.model_validate( + {**SETTINGS.model_dump(exclude_unset=True), **updates, "bind_password": password} + ) + assert password not in str(error.value) + + def test_cancelled_reader_stops_before_opening_ldap(): cancellation = Event() cancellation.set()