REDHAT-BUG-2529697: Use After Free
SUMMARY A double-free / use-after-free exists in the SAX attributeDecl callback handler (pythonAttributeDecl in python/libxml.c). When parsing XML containing a DTD <!ATTLIST> declaration with enumerated attribute values, each value string is freed twice: PyListSetItem() steals the reference, and an explicit PyDECREF() then drops the refcount to zero and frees the object, leaving a dangling pointer in the list.
AFFECTED COMPONENT
libxml2 with Python bindings enabled (python3-libxml2 / libxml2-python)
The defect is long-standing; the affected code in pythonAttributeDecl has been unchanged for many years.
Reproduced on upstream commit 4b35628e97472eaf23d8a841d2f711f7c2f96255 (2026-02-24).
IMPACT
Denial of service: 100% reproducible crash (SIGSEGV) in any Python application that uses the libxml2 SAX bindings (libxml2.createPushParser), registers an attributeDecl handler, and parses untrusted XML with a DTD <!ATTLIST> containing enumerated values. Verified 10/10 in isolated processes.
The use-after-free is also potentially exploitable for code execution: I was able to demonstrate hijacking the freed object's tpdealloc function pointer in-process. Full remote code execution would require additional heap grooming and is not demonstrated. I'd defer to your team on final severity scoring; I'd characterize the reliably demonstrated impact as DoS, with code execution as a credible but conditional escalation.
ROOT CAUSE (python/libxml.c, pythonAttributeDecl)
for (node = tree; node != NULL; node = node->next) { newName = PYIMPORTSTRING((char ) node->name); PyListSetItem(nameList, count, newName); / steals reference / PyDECREF(newName); / double-free / count++; }
PyListSetItem() does not increment the refcount, so the subsequent PyDECREF() over-decrements. Because of CPython pymalloc free-list reuse, list entries can end up pointing at the same freed address; cleanup after the SAX callback then decrefs dangling pointers and corrupts allocator state.
PROOF OF CONCEPT (minimal DoS)
import libxml2 class Handler: def attributeDecl(self, args): pass def startElement(self, a): pass def endElement(self, a): pass def characters(self, a): pass xml = b'''<?xml version="1.0"?> <!DOCTYPE r [ <!ELEMENT r EMPTY> <!ATTLIST r a (xx|yy|zz|ww|qq) "xx"> ]> <r a="xx"/>''' h = Handler() c = libxml2.createPushParser(h, "", 0, "t") c.parseChunk(xml, len(xml), 1) # SIGSEGV
UPSTREAM FIX (already merged and closed)
Fix: remove the erroneous PyDECREF(newName) since PyListSetItem already takes ownership.
Merge request: https://gitlab.gnome.org/GNOME/libxml2/-/mergerequests/397 ("python: Do not decref string after adding to the list")
Fix commit: 046931e6
Issue report: https://gitlab.gnome.org/GNOME/libxml2/-/workitems/1076
Upstream maintainer Nick Wellnhofer confirmed it appears to be a security issue and asked that a CVE be requested; the maintainer who merged the fix indicated CVE assignment is not handled by the project itself.
SUGGESTED CLASSIFICATION
CWE-415 (Double Free), leading to CWE-416 (Use After Free)
ENVIRONMENT
OS: Ubuntu 22.04 x8664; Python 3.10.12; GCC 11.4.0; libxml2 built from source with -fsanitize=address.
I'm happy to provide the full ASan trace or the code-execution PoC on request. Please let me know if you need anything else to proceed.
Thank you, Adnan Jakati!https://mailtrack.io/trace/mail/773e02eeb348f92b41f2a5d93b4c46af0007ab1f.png?u=12519192!
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
libxml2-python (libxml2 createPushParser / SAX bindings, python/libxml.c pythonAttributeDecl)to a version that resolves this vulnerability.Patch 046931e6
Event History
Frequently Asked Questions
Which deployments should be prioritized for triage?
Prioritize Python applications using the libxml2 SAX bindings through libxml2.createPushParser, particularly where python3-libxml2 or libxml2-python is installed and the application processes untrusted XML.
What input and application behavior are required to trigger the crash?
The application must register an attributeDecl handler and parse XML containing a DTD <!ATTLIST> declaration with enumerated attribute values. Under those conditions, the issue was reported as a 100% reproducible SIGSEGV in isolated-process testing.
Is the impact limited to denial of service?
A denial of service crash is confirmed. The report also describes an in-process demonstration of hijacking the freed object's tp_dealloc function pointer, so code execution is considered potentially possible, but full remote code execution is not confirmed in the provided data.