T09 · Insecure Skill Coding Practices
- Location
scripts/contract_review_pipeline.py:50- Finding
Unsafe Parsing of Attacker-Controlled DOCX XML
- Content
View full analysis
Vulnerability Details
File Location:
scripts/contract_review_pipeline.py:50-51
Related Call Sites:scripts/contract_review_pipeline.py:78-79,scripts/contract_review_pipeline.py:210-211, andscripts/contract_review_pipeline.py:360-361
Vulnerability Type: Unsafe XML parsing
Risk Level: MediumVulnerable Code
python def parse_xml(data: bytes) -> etree._Element: return etree.fromstring(data)Attacker-controlled DOCX members are passed to this function, including:
python comments_root = parse_xml(archive.read("word/comments.xml")) document_root = parse_xml(archive.read("word/document.xml"))python document_xml = read_docx_member(input_docx, "word/document.xml") root = parse_xml(document_xml)python document_root = parse_xml(original_files["word/document.xml"]) settings_root = parse_xml(original_files["word/settings.xml"])Technical Analysis
A DOCX document is a ZIP archive containing XML files. The skill processes user-supplied DOCX files and parses their
document.xml,comments.xml, andsettings.xmlmembers throughlxml.etree.fromstring()without supplying an explicitly hardened XML parser.The implementation does not explicitly disable:
- DTD processing
- XML entity resolution
- Network-based resource resolution
- Oversized XML tree handling
Consequently, its security depends on implicit lxml and libxml2 defaults, which can vary by version and runtime configuration. A crafted document containing malicious declarations or resource-intensive XML structures could expose the process to entity expansion, unintended local-resource resolution, or parser-based denial of service.
The surrounding ZIP-processing code also reads relevant members into memory without enforcing per-member or aggregate uncompressed-size limits. This can amplify denial-of-service risk when maliciously compressed or oversized DOCX content is supplied.
Attack Path
- An attacker creates a DOCX archive cont ...[truncated 1335 chars]
- Remediation
View remediation
Remediation Suggestions
Create and use an explicitly hardened XML parser rather than relying on library defaults:
python def parse_xml(data: bytes) -> etree._Element: parser = etree.XMLParser( resolve_entities=False, load_dtd=False, no_network=True, huge_tree=False, ) return etree.fromstring(data, parser=parser)Apply the following additional controls:
- Reject XML documents containing a
DOCTYPEdeclaration before parsing. - Enforce a maximum compressed and uncompressed size for each DOCX member.
- Enforce a maximum aggregate uncompressed size for the entire DOCX archive.
- Reject duplicate, unexpected, encrypted, or suspicious archive entries.
- Limit XML nesting depth, paragraph count, comment count, and extracted text size.
- Catch
zipfile,lxml, memory, and malformed-document errors and fail closed with a safe diagnostic. - Test the parser against entity-expansion payloads, external-entity payloads, deeply nested XML, oversized XML members, and ZIP bombs.
- Process untrusted contracts in a resource-constrained environment where practical.
- Reject XML documents containing a
