XML bomb protection for Python stdlib modules
—
DefusedXML provides a comprehensive exception hierarchy for handling XML security violations and library-specific errors. All exceptions inherit from the base DefusedXmlException class, which itself inherits from ValueError.
Base exception class for all defusedxml security violations and errors.
class DefusedXmlException(ValueError):
"""
Base exception for all defusedxml security violations and errors.
Inherits from ValueError to maintain compatibility with standard XML
processing error handling patterns.
"""
def __repr__(self):
"""Return string representation of the exception"""Exception raised when document type definition (DTD) processing is attempted but forbidden by security settings.
class DTDForbidden(DefusedXmlException):
"""
Raised when DTD processing is attempted but forbidden.
DTD processing can be exploited for external entity attacks and
DTD processing attacks that can access local files or make
network requests.
Attributes:
name (str): The name of the DTD
sysid (str): System identifier of the DTD
pubid (str): Public identifier of the DTD
"""
def __init__(self, name, sysid, pubid):
"""
Initialize DTDForbidden exception.
Args:
name (str): The name of the DTD
sysid (str): System identifier of the DTD
pubid (str): Public identifier of the DTD
"""
def __str__(self):
"""Return formatted string representation"""Usage Example:
import defusedxml.ElementTree as ET
xml_with_dtd = '''<?xml version="1.0"?>
<!DOCTYPE root SYSTEM "http://example.com/malicious.dtd">
<root>content</root>'''
try:
# This will raise DTDForbidden with default settings
root = ET.fromstring(xml_with_dtd, forbid_dtd=True)
except defusedxml.DTDForbidden as e:
print(f"DTD processing blocked: {e}")
print(f"DTD name: {e.name}")
print(f"System ID: {e.sysid}")
print(f"Public ID: {e.pubid}")Exception raised when entity processing is attempted but forbidden by security settings.
class EntitiesForbidden(DefusedXmlException):
"""
Raised when entity processing is attempted but forbidden.
Entity processing can be exploited for billion laughs attacks,
quadratic blowup attacks, and external entity attacks that can
consume excessive memory or access external resources.
Attributes:
name (str): The name of the entity
value (str): The value of the entity (may be None)
base (str): Base URI for resolving relative references
sysid (str): System identifier of the entity
pubid (str): Public identifier of the entity
notation_name (str): Notation name for unparsed entities
"""
def __init__(self, name, value, base, sysid, pubid, notation_name):
"""
Initialize EntitiesForbidden exception.
Args:
name (str): The name of the entity
value (str): The value of the entity (may be None)
base (str): Base URI for resolving relative references
sysid (str): System identifier of the entity
pubid (str): Public identifier of the entity
notation_name (str): Notation name for unparsed entities
"""
def __str__(self):
"""Return formatted string representation"""Usage Example:
import defusedxml.ElementTree as ET
xml_with_entities = '''<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
]>
<root>&lol2;</root>'''
try:
# This will raise EntitiesForbidden with default settings
root = ET.fromstring(xml_with_entities)
except defusedxml.EntitiesForbidden as e:
print(f"Entity processing blocked: {e}")
print(f"Entity name: {e.name}")
print(f"Entity value: {e.value}")Exception raised when external reference processing is attempted but forbidden by security settings.
class ExternalReferenceForbidden(DefusedXmlException):
"""
Raised when external reference processing is attempted but forbidden.
External references can be exploited for server-side request forgery
(SSRF) attacks, local file access, and network reconnaissance by
forcing the parser to make HTTP requests or access local files.
Attributes:
context (str): Context information about the reference
base (str): Base URI for resolving relative references
sysid (str): System identifier of the external reference
pubid (str): Public identifier of the external reference
"""
def __init__(self, context, base, sysid, pubid):
"""
Initialize ExternalReferenceForbidden exception.
Args:
context (str): Context information about the reference
base (str): Base URI for resolving relative references
sysid (str): System identifier of the external reference
pubid (str): Public identifier of the external reference
"""
def __str__(self):
"""Return formatted string representation"""Usage Example:
import defusedxml.ElementTree as ET
xml_with_external = '''<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY external SYSTEM "file:///etc/passwd">
]>
<root>&external;</root>'''
try:
# This will raise ExternalReferenceForbidden with default settings
root = ET.fromstring(xml_with_external)
except defusedxml.ExternalReferenceForbidden as e:
print(f"External reference blocked: {e}")
print(f"System ID: {e.sysid}")
print(f"Public ID: {e.pubid}")Exception raised when an operation is not supported by the defused implementation.
class NotSupportedError(DefusedXmlException):
"""
Raised when an operation is not supported by the defused implementation.
Some XML processing features are intentionally not supported in defused
implementations to maintain security, or may not be available in certain
configurations or library versions.
"""Usage Example:
import defusedxml.lxml as lxml_defused
try:
# iterparse is not supported in defused lxml
parser = lxml_defused.iterparse('document.xml')
except defusedxml.NotSupportedError as e:
print(f"Operation not supported: {e}")ValueError
└── DefusedXmlException
├── DTDForbidden
├── EntitiesForbidden
├── ExternalReferenceForbidden
└── NotSupportedErrorimport defusedxml.ElementTree as ET
import defusedxml
def safe_parse_xml(xml_content):
"""Safely parse XML with comprehensive error handling."""
try:
return ET.fromstring(xml_content)
except ET.ParseError as e:
print(f"XML syntax error: {e}")
return None
except defusedxml.DTDForbidden as e:
print(f"DTD processing forbidden: {e}")
return None
except defusedxml.EntitiesForbidden as e:
print(f"Entity processing forbidden: {e}")
return None
except defusedxml.ExternalReferenceForbidden as e:
print(f"External reference forbidden: {e}")
return None
except defusedxml.DefusedXmlException as e:
print(f"Other defusedxml error: {e}")
return Noneimport defusedxml.ElementTree as ET
import defusedxml
def parse_with_fallback(xml_content, allow_dtd=False):
"""Parse XML with security fallbacks."""
try:
return ET.fromstring(xml_content, forbid_dtd=not allow_dtd)
except defusedxml.DTDForbidden:
if not allow_dtd:
# Retry with DTD allowed
return ET.fromstring(xml_content, forbid_dtd=False)
raise
except (defusedxml.EntitiesForbidden, defusedxml.ExternalReferenceForbidden):
# These are always security risks, don't retry
raiseInstall with Tessl CLI
npx tessl i tessl/pypi-defusedxml