T09 · Insecure Skill Coding Practices
- Location
scripts/extract_documents.py:77- Finding
Unbounded DOCX Decompression and XML Parsing Can Cause Denial of Service
- Content
View full analysis
Vulnerability Details
File Location:
scripts/extract_documents.py, lines 77–92
Vulnerability Type: Uncontrolled resource consumption during archive decompression and XML parsing
Risk Level: MediumVulnerable Code
python with zipfile.ZipFile(path) as archive: names = set(archive.namelist()) if "word/document.xml" not in names: raise ValueError("DOCX 缺少 word/document.xml") for part in parts: if part not in names: continue root = ET.fromstring(archive.read(part)) for paragraph in root.iter(W_NS + "p"): chunks: list[str] = [] for node in paragraph.iter(): if node.tag == W_NS + "t" and node.text: chunks.append(node.text) elif node.tag == W_NS + "tab": chunks.append("\t") elif node.tag in {W_NS + "br", W_NS + "cr"}: chunks.append("\n")Technical Analysis
The document extractor treats user-provided DOCX files as ZIP archives and reads selected OOXML entries directly into memory with
archive.read(part). It does not enforce limits on:- Compressed archive size
- Uncompressed entry size
- Aggregate uncompressed size
- Compression ratio
- XML depth or node count
- Memory or CPU consumption
A malicious DOCX can contain a highly compressed or extremely large
word/document.xml,word/footnotes.xml, orword/endnotes.xml. Callingarchive.read(part)fully decompresses the selected entry into memory.ET.fromstring(...)then constructs an additional in-memory XML tree, further increasing resource use.Although the parser does not appear vulnerable to external entity expansion, the missing resource limits permit archive-bomb or oversized-XML denial-of-service attacks.
Attack Path
- An attacker creates a syntactically valid DOCX archive.
- The archive includes
word/document.xmlor another processed OOXML entry with an extremely large unco ...[truncated 1229 chars]
- Remediation
View remediation
Remediation Suggestions
- Inspect every relevant
ZipInfoobject before decompression and reject entries exceeding a configured uncompressed-size limit. - Enforce a maximum aggregate uncompressed size across all processed OOXML entries.
- Reject suspicious compression ratios by comparing
ZipInfo.file_sizewithZipInfo.compress_size. - Limit the number of archive entries and reject malformed or unexpectedly complex DOCX packages.
- Replace full-buffer reads with bounded streaming or incremental XML parsing.
- Enforce maximum XML depth, node count, text length, and parsing duration where practical.
- Process untrusted documents in a sandbox with strict memory, CPU, file-size, and execution-time limits.
- Add regression tests for oversized XML, high-compression-ratio entries, excessive node counts, and malformed archives.
- Return a controlled validation error when any resource budget is exceeded rather than attempting to parse the document.
- Inspect every relevant
