I love good, simple Python libraries that improve security in a simple, straightforward way. The ideal solution is a well-designed module that has minimal external dependencies and meets key criteria on my checklist for Python Security Applications.
By easy to use, I mean adding just one decorator on top of a function that processes XML.
Processing a vulnerable XML file can have dramatic consequences. With just a few hundred bytes of XML data, an attacker can occupy several gigabytes of memory within seconds. An attacker can also keep CPUs busy for a long time with a small- to medium-sized request. Under some circumstances, it is even possible to access local files on your server, circumvent a firewall, or abuse services to rebound attacks onto third parties.
The majority of Python developers are not security experts, and nor should they have to be! However, AI tools offer little assistance, as LLMs are trained on massive amounts of insecure codebases.
Issues with vulnerable XML files are not new — they have been known for a long time. The Billion Laughs attack was first reported in 2003. Nevertheless, many newly created applications and Python scripts remain vulnerable because decent security checks are often missing.
As a Python developer, you cannot and should not rely on just any XML parsing library. Python’s standard xml library is not secure by default, and the ever-growing list of issues shows that security is your responsibility.
Even if you use an external XML library when processing XML in Python, such as the great lxml library, you should still apply the key defence-in-depth principle, as lxml also has only a limited number of security validations turned on by default. By default, lxml can be vulnerable to XML External Entity (XXE) injection and Billion Laughs (entity expansion) attacks if external entities are not explicitly disabled.
Processing untrusted XML files without validation can lead to:
- Billion Laughs Attack (exponential entity expansion causing memory exhaustion)
- Deep Nesting Attacks (extreme nesting depth causing stack overflows)
- Attribute Bomb (excessive attributes per element causing DoS)
- Large Text Nodes (massive text or attribute values consuming memory)
- DTD/DOCTYPE Attacks (external entity resolution, XXE, and internal DTD bombs)
- GZip Bomb (compressed XML with extreme decompression ratios)
- Malformed XML (causing parser crashes or infinite loops)
A straightforward way to secure XML handling in your application is to use the Python FileAudit library alongside its validate_xml decorator.
Usage is simple:
# Validate a local XML file
result = validate_xml("path/to/file.xml", max_depth=50)
# Validate remote file (HTTPS only)
result = validate_xml("https://example.com/data.xml", max_file_size=10*1024*1024)
# Returns True if valid, False if invalid (errors printed to stdout)p
Or just use a decorator before processing any xml file:
# Bare decorator (uses default limits)
@validate_xml
def process_data(file_path):
# XML already validated before function body runs
return parse_xml(file_path)
By default the Python File Audit xml_validation functionality offers the following security capabilities:
DDoS Protection Features:
- Document Size Limiting: Enforces maximum file size to prevent memory exhaustion
- Deep Nesting Protection: Limits XML element nesting depth to prevent stack overflow
- Element Count Limiting: Caps total number of elements in the document
- Attribute Explosion Protection: Limits maximum attributes per element
- Text Node Size Protection: Enforces maximum length for text nodes and attribute values
- Name Length Validation: Limits length of element and attribute names
Security Features:
- DOCTYPE Rejection: Blocks all DTD/DOCTYPE declarations (prevents XXE and entity attacks)
- External Entity Blocking: DOCTYPE rejection eliminates external entity resolution risk
- Element and Attribute Count Limits: Prevents resource exhaustion through excessive elements/attributes
- Depth Limiting: Prevents stack overflow from deeply nested XML
- Name Length Validation: Prevents buffer overflows from extremely long names
- Text Length Validation: Prevents memory exhaustion from oversized text/attribute values
- UTF-8 Strict Validation: Rejects files with invalid UTF-8 encoding
- GZip Compression Handling: Supports compressed XML with size limits during decompression
- Remote HTTPS-Only Support: Strictly restricts remote files to HTTPS URLs only
Getting started with this very simple security library to harden your Python scripts is easy:
pip install fileaudit
Check all information and more examples in the manual!
