Action not permitted
Modal body text goes here.
Modal Title
Modal Body
GHSA-P34H-WQ7J-H5V6
Vulnerability from github – Published: 2025-10-10 22:53 – Updated: 2025-10-13 15:47Summary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "python-ldap"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.4.5"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-61912"
],
"database_specific": {
"cwe_ids": [
"CWE-116",
"CWE-170"
],
"github_reviewed": true,
"github_reviewed_at": "2025-10-10T22:53:25Z",
"nvd_published_at": "2025-10-10T22:15:37Z",
"severity": "MODERATE"
},
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "GHSA-p34h-wq7j-h5v6",
"modified": "2025-10-13T15:47:44Z",
"published": "2025-10-10T22:53:25Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination"
}
BREW-ANSIBLE-CVE-2025-61912 (GHSA-P34H-WQ7J-H5V6)
Vulnerability from osv_homebrew – Published: 2026-08-13 16:35 – Updated: 2026-09-30 18:44 – Source websiteSummary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "python-ldap",
"resource_purl": "pkg:pypi/python-ldap@3.4.8",
"upstream_fixed_in": "3.4.5"
},
"package": {
"ecosystem": "Homebrew",
"name": "ansible",
"purl": "pkg:brew/ansible"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "14.3.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/python-ldap@3.4.8",
"name": "python-ldap",
"resource": "python-ldap",
"strategy": "registry",
"subject_version": "3.4.8"
}
]
},
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "BREW-ansible-CVE-2025-61912",
"modified": "2026-09-30T18:44:09Z",
"published": "2026-08-13T16:35:22Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination",
"upstream": [
"GHSA-p34h-wq7j-h5v6",
"CVE-2025-61912",
"PYSEC-2026-1846"
]
}
BREW-ANSIBLE@10-CVE-2025-61912 (GHSA-P34H-WQ7J-H5V6)
Vulnerability from osv_homebrew – Published: 2026-08-13 16:35 – Updated: 2026-09-09 23:41 – Source websiteSummary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "python-ldap",
"resource_purl": "pkg:pypi/python-ldap@3.4.5",
"upstream_fixed_in": "3.4.5"
},
"package": {
"ecosystem": "Homebrew",
"name": "ansible@10",
"purl": "pkg:brew/ansible%4010"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "10.7.0_6"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/python-ldap@3.4.5",
"name": "python-ldap",
"resource": "python-ldap",
"strategy": "registry",
"subject_version": "3.4.5"
}
]
},
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "BREW-ansible@10-CVE-2025-61912",
"modified": "2026-09-09T23:41:06Z",
"published": "2026-08-13T16:35:22Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination",
"upstream": [
"GHSA-p34h-wq7j-h5v6",
"CVE-2025-61912",
"PYSEC-2026-1846"
]
}
BREW-ANSIBLE@12-CVE-2025-61912 (GHSA-P34H-WQ7J-H5V6)
Vulnerability from osv_homebrew – Published: 2026-08-13 16:35 – Updated: 2026-09-09 23:41 – Source websiteSummary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "python-ldap",
"resource_purl": "pkg:pypi/python-ldap@3.4.5",
"upstream_fixed_in": "3.4.5"
},
"package": {
"ecosystem": "Homebrew",
"name": "ansible@12",
"purl": "pkg:brew/ansible%4012"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "12.3.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/python-ldap@3.4.5",
"name": "python-ldap",
"resource": "python-ldap",
"strategy": "registry",
"subject_version": "3.4.5"
}
]
},
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "BREW-ansible@12-CVE-2025-61912",
"modified": "2026-09-09T23:41:06Z",
"published": "2026-08-13T16:35:22Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination",
"upstream": [
"GHSA-p34h-wq7j-h5v6",
"CVE-2025-61912",
"PYSEC-2026-1846"
]
}
BREW-ANSIBLE@13-CVE-2025-61912 (GHSA-P34H-WQ7J-H5V6)
Vulnerability from osv_homebrew – Published: 2026-08-13 16:35 – Updated: 2026-09-10 18:51 – Source websiteSummary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "python-ldap",
"resource_purl": "pkg:pypi/python-ldap@3.4.7",
"upstream_fixed_in": "3.4.5"
},
"package": {
"ecosystem": "Homebrew",
"name": "ansible@13",
"purl": "pkg:brew/ansible%4013"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "13.8.0_2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/python-ldap@3.4.7",
"name": "python-ldap",
"resource": "python-ldap",
"strategy": "registry",
"subject_version": "3.4.7"
}
]
},
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "BREW-ansible@13-CVE-2025-61912",
"modified": "2026-09-10T18:51:29Z",
"published": "2026-08-13T16:35:22Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination",
"upstream": [
"GHSA-p34h-wq7j-h5v6",
"CVE-2025-61912",
"PYSEC-2026-1846"
]
}
BREW-ANSIBLE@9-CVE-2025-61912 (GHSA-P34H-WQ7J-H5V6)
Vulnerability from osv_homebrew – Published: 2026-08-13 16:35 – Updated: 2026-09-09 23:41 – Source websiteSummary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
{
"affected": [
{
"ecosystem_specific": {
"fix": "bump",
"range_state": "fixed",
"resource": "python-ldap",
"resource_purl": "pkg:pypi/python-ldap@3.4.5",
"upstream_fixed_in": "3.4.5"
},
"package": {
"ecosystem": "Homebrew",
"name": "ansible@9",
"purl": "pkg:brew/ansible%409"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "9.13.0_4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"database_specific": {
"confidence": "high",
"source": "matched",
"strategy": "registry",
"upstream_evidence": [
{
"ecosystem": "PyPI",
"key": "pkg:pypi/python-ldap@3.4.5",
"name": "python-ldap",
"resource": "python-ldap",
"strategy": "registry",
"subject_version": "3.4.5"
}
]
},
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "BREW-ansible@9-CVE-2025-61912",
"modified": "2026-09-09T23:41:06Z",
"published": "2026-08-13T16:35:23Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"schema_version": "1.7.3",
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination",
"upstream": [
"GHSA-p34h-wq7j-h5v6",
"CVE-2025-61912",
"PYSEC-2026-1846"
]
}
CVE-2025-61912 (GCVE-0-2025-61912)
Vulnerability from cvelistv5 – Published: 2025-10-10 22:04 – Updated: 2025-10-14 14:58| URL | Tags |
|---|---|
| https://github.com/python-ldap/python-ldap/securi… | x_refsource_CONFIRM |
| https://github.com/python-ldap/python-ldap/commit… | x_refsource_MISC |
| https://github.com/python-ldap/python-ldap/releas… | x_refsource_MISC |
| Vendor | Product | Version | |
|---|---|---|---|
| python-ldap | python-ldap |
Affected:
< 3.4.5
|
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2025-61912",
"options": [
{
"Exploitation": "poc"
},
{
"Automatable": "no"
},
{
"Technical Impact": "partial"
}
],
"role": "CISA Coordinator",
"timestamp": "2025-10-14T14:57:58.750366Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2025-10-14T14:58:06.682Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"cna": {
"affected": [
{
"product": "python-ldap",
"vendor": "python-ldap",
"versions": [
{
"status": "affected",
"version": "\u003c 3.4.5"
}
]
}
],
"descriptions": [
{
"lang": "en",
"value": "python-ldap is a lightweight directory access protocol (LDAP) client API for Python. In versions prior to 3.4.5, 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. Version 3.4.5 contains a patch for the issue."
}
],
"metrics": [
{
"cvssV4_0": {
"attackComplexity": "LOW",
"attackRequirements": "NONE",
"attackVector": "NETWORK",
"baseScore": 5.5,
"baseSeverity": "MEDIUM",
"privilegesRequired": "NONE",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "NONE",
"userInteraction": "NONE",
"vectorString": "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",
"version": "4.0",
"vulnAvailabilityImpact": "LOW",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "NONE"
}
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-116",
"description": "CWE-116: Improper Encoding or Escaping of Output",
"lang": "en",
"type": "CWE"
}
]
},
{
"descriptions": [
{
"cweId": "CWE-170",
"description": "CWE-170: Improper Null Termination",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2025-10-10T22:04:25.028Z",
"orgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"shortName": "GitHub_M"
},
"references": [
{
"name": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6",
"tags": [
"x_refsource_CONFIRM"
],
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"name": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f",
"tags": [
"x_refsource_MISC"
],
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"name": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5",
"tags": [
"x_refsource_MISC"
],
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
}
],
"source": {
"advisory": "GHSA-p34h-wq7j-h5v6",
"discovery": "UNKNOWN"
},
"title": "python-ldap Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination"
}
},
"cveMetadata": {
"assignerOrgId": "a0819718-46f1-4df5-94e2-005712e83aaa",
"assignerShortName": "GitHub_M",
"cveId": "CVE-2025-61912",
"datePublished": "2025-10-10T22:04:25.028Z",
"dateReserved": "2025-10-03T22:21:59.614Z",
"dateUpdated": "2025-10-14T14:58:06.682Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.1"
}
PYSEC-2026-1846
Vulnerability from pysec - Published: 2026-07-07 16:03 - Updated: 2026-07-07 17:25Summary
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 escape_dn_chars, str2dn
l = ldap.initialize("ldap://10.0.1.11") # your lab DC/LDAP l.protocol_version = 3 l.set_option(ldap.OPT_REFERRALS, 0) l.simple_bind_s(r"DSEC\dani.aga", "PassAa1")
--- Attacker-controlled value contains NUL ---
cn = "bad\0name" escaped_cn = escape_dn_chars(cn) dn = f"CN={escaped_cn},OU=Users,DC=dsec,DC=local" attrs = [('objectClass', [b'user']), ('sAMAccountName', [b'badsam'])]
print("=== BUGGY DN (contains literal NUL) ===") print("escaped_cn repr:", repr(escaped_cn)) print("dn repr:", repr(dn)) print("contains NUL?:", "\x00" in dn, "at index:", dn.find("\x00"))
print("=> add_s(buggy DN): expected client-side failure (no server contact)") try: l.add_s(dn, attrs) print("add_s(buggy): succeeded (unexpected)") except Exception as e: print("add_s(buggy):", type(e).name, e) # ValueError: embedded null character
--- Correct hex escape demonstrates the client proceeds to the server ---
safe_dn = dn.replace("\x00", r"\00") # RFC 4514-compliant print("\n=== HEX-ESCAPED DN (\00) ===") print("safe_dn repr:", repr(safe_dn)) print("=> sanity parse:", str2dn(safe_dn)) # parses locally
print("=> add_s(safe DN): reaches server (AD will likely reject with 34)") try: l.add_s(safe_dn, attrs) print("add_s(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.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.
| Name | purl | python-ldap | pkg:pypi/python-ldap |
|---|
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "python-ldap",
"purl": "pkg:pypi/python-ldap"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "3.4.5"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"2.3.13",
"2.4.0",
"2.4.1",
"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.2",
"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.3",
"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.4",
"2.4.40",
"2.4.41",
"2.4.42",
"2.4.43",
"2.4.44",
"2.4.45",
"2.4.5",
"2.4.6",
"2.4.7",
"2.4.8",
"2.4.9",
"2.5.1",
"2.5.2",
"3.0.0",
"3.0.0b1",
"3.0.0b2",
"3.0.0b3",
"3.0.0b4",
"3.1.0",
"3.2.0",
"3.3.0",
"3.3.1",
"3.4.0",
"3.4.2",
"3.4.3",
"3.4.4"
]
}
],
"aliases": [
"CVE-2025-61912",
"GHSA-p34h-wq7j-h5v6"
],
"details": "### 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(\u0027\\000\u0027, \u0027\\\\\\000\u0027) # 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 \u201cshould be used when building LDAP DN strings from arbitrary input.\u201d The function\u2019s 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(\u0027\\x00\u0027, r\u0027\\00\u0027)`\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 = [(\u0027objectClass\u0027, [b\u0027user\u0027]), (\u0027sAMAccountName\u0027, [b\u0027badsam\u0027])]\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(\"=\u003e 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(\"=\u003e sanity parse:\", str2dn(safe_dn)) # parses locally\n\nprint(\"=\u003e 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` \u2190 client-side DoS\n\n`add_s(safe): INVALID_DN_SYNTAX (result 34, BAD_NAME)` \u2190 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\u2014e.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.",
"id": "PYSEC-2026-1846",
"modified": "2026-07-07T17:25:14.271126Z",
"published": "2026-07-07T16:03:07.472350Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/security/advisories/GHSA-p34h-wq7j-h5v6"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-61912"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/commit/6ea80326a34ee6093219628d7690bced50c49a3f"
},
{
"type": "PACKAGE",
"url": "https://github.com/python-ldap/python-ldap"
},
{
"type": "WEB",
"url": "https://github.com/python-ldap/python-ldap/releases/tag/python-ldap-3.4.5"
},
{
"type": "PACKAGE",
"url": "https://pypi.org/project/python-ldap"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-p34h-wq7j-h5v6"
}
],
"severity": [
{
"score": "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",
"type": "CVSS_V4"
}
],
"summary": "python-ldap is Vulnerable to Improper Encoding or Escaping of Output and Improper Null Termination"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.