From 09d2b7eeb0e330df73b1aef0cba57788fde52b6b Mon Sep 17 00:00:00 2001 From: Khushboo Vashi Date: Mon, 10 Nov 2025 11:26:04 +0530 Subject: [PATCH] 1) Fixed LDAP authentication flow vulnerable to TLS certificate verification bypass (CVE-2025-12765). #9324 2) Fixed LDAP injection vulnerability in LDAP authentication flow (CVE-2025-12764). #9325 --- docs/en_US/ldap.rst | 2 ++ docs/en_US/release_notes_9_10.rst | 4 +++- web/config.py | 3 +++ web/pgadmin/authenticate/ldap.py | 13 +++++++------ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/en_US/ldap.rst b/docs/en_US/ldap.rst index 59fb9d8b0..b8f598d62 100644 --- a/docs/en_US/ldap.rst +++ b/docs/en_US/ldap.rst @@ -87,6 +87,8 @@ There are 3 ways to configure LDAP: "LDAP_KEY_FILE","Specifies the path to the server private key file. This parameter is applicable only if you are using *ldaps* as connection protocol or you have set *LDAP_USE_STARTTLS* parameter to *True*." + "LDAP_CERT_VALIDATE", "Set this parameter to *False* if you want to bypass + the TLS certificate validation. By default it is set to True." "LDAP_IGNORE_MALFORMED_SCHEMA", "Some flaky LDAP servers returns malformed schema. If this parameter set to *True*, no exception will be raised and schema is thrown away but authentication will be done. This parameter should remain False, as recommended." diff --git a/docs/en_US/release_notes_9_10.rst b/docs/en_US/release_notes_9_10.rst index 74a0d11a3..1f00368a1 100644 --- a/docs/en_US/release_notes_9_10.rst +++ b/docs/en_US/release_notes_9_10.rst @@ -42,4 +42,6 @@ Bug fixes | `Issue #9281 `_ - Fixed an issue where the last used storage directory was reset to blank, leading to access denied errors during backup or restore operations. | `Issue #9304 `_ - Fixed an issue that prevented assigning multiple users to an RLS policy. | `Issue #9320 `_ - Fixed remote code execution vulnerability when restoring PLAIN-format SQL dumps in server mode (CVE-2025-12762). - | `Issue #9323 `_ - Fixed Command injection vulnerability allowing arbitrary command execution on Windows (CVE-2025-12763). \ No newline at end of file + | `Issue #9323 `_ - Fixed Command injection vulnerability allowing arbitrary command execution on Windows (CVE-2025-12763). + | `Issue #9324 `_ - Fixed LDAP authentication flow vulnerable to TLS certificate verification bypass (CVE-2025-12765). + | `Issue #9325 `_ - Fixed LDAP injection vulnerability in LDAP authentication flow (CVE-2025-12764). \ No newline at end of file diff --git a/web/config.py b/web/config.py index 155a09552..37b2291ed 100644 --- a/web/config.py +++ b/web/config.py @@ -754,6 +754,9 @@ LDAP_CA_CERT_FILE = '' LDAP_CERT_FILE = '' LDAP_KEY_FILE = '' +# TLS/SSL certificate Validation (True/False), +# Make it false if certificate validation is not required. +LDAP_CERT_VALIDATE = True ########################################################################## # Some flaky LDAP servers returns malformed schema. If True, no exception diff --git a/web/pgadmin/authenticate/ldap.py b/web/pgadmin/authenticate/ldap.py index 65ad8196e..53b91c378 100644 --- a/web/pgadmin/authenticate/ldap.py +++ b/web/pgadmin/authenticate/ldap.py @@ -16,6 +16,7 @@ from ldap3 import Connection, Server, Tls, ALL, ALL_ATTRIBUTES, ANONYMOUS,\ from ldap3.core.exceptions import LDAPSocketOpenError, LDAPBindError,\ LDAPInvalidScopeError, LDAPAttributeError, LDAPInvalidFilterError,\ LDAPStartTLSError, LDAPSSLConfigurationError +from ldap3.utils.conv import escape_filter_chars from flask_babel import gettext from urllib.parse import urlparse @@ -212,10 +213,8 @@ class LDAPAuthentication(BaseAuthentication): ca_cert_file = getattr(config, 'LDAP_CA_CERT_FILE', None) cert_file = getattr(config, 'LDAP_CERT_FILE', None) key_file = getattr(config, 'LDAP_KEY_FILE', None) - cert_validate = ssl.CERT_NONE - - if ca_cert_file and cert_file and key_file: - cert_validate = ssl.CERT_REQUIRED + cert_required = getattr(config, 'LDAP_CERT_VALIDATE', True) + cert_validate = ssl.CERT_REQUIRED if cert_required else ssl.CERT_NONE try: tls = Tls( @@ -278,8 +277,10 @@ class LDAPAuthentication(BaseAuthentication): elif not search_base_dn or search_base_dn == '': search_base_dn = config.LDAP_BASE_DN - search_filter = "({0}={1})".format(config.LDAP_USERNAME_ATTRIBUTE, - self.username) + search_filter = "({0}={1})".format( + config.LDAP_USERNAME_ATTRIBUTE, + escape_filter_chars(self.username) + ) if config.LDAP_SEARCH_FILTER: search_filter = "(&{0}{1})".format(search_filter, config.LDAP_SEARCH_FILTER)