T09 · Insecure Skill Coding Practices
- Location
scripts/docx_to_md.py:28- Finding
Unbounded DOCX Archive Extraction Enables Resource Exhaustion
- Content
View full analysis
Vulnerability Details
File Location:
scripts/docx_to_md.py, lines 28–41
Vulnerability Type: Unbounded archive extraction and processing
Risk Level: MediumVulnerable Code
python image_files = [] with zipfile.ZipFile(doc_path, 'r') as zip_ref: media_files = [f for f in zip_ref.namelist() if f.startswith('word/media/') and not f.endswith('/')] for i, img_file in enumerate(media_files): ext = os.path.splitext(img_file)[1] img_name = f"image_{i+1}{ext}" zip_ref.extract(img_file, output_dir) old_path = os.path.join(output_dir, img_file) new_path = os.path.join(output_dir, img_name) if os.path.exists(old_path): os.rename(old_path, new_path) image_files.append(img_name)Technical Analysis
A DOCX file is a ZIP archive. The converter extracts every non-directory archive member under
word/media/without validating:- The number of media members.
- The uncompressed size of each member.
- The cumulative uncompressed size.
- The compression ratio.
- Available disk space or processing limits.
Calling
ZipFile.extract()on every matching member permits a crafted DOCX containing numerous files or highly compressed, oversized media to consume excessive disk space and CPU. The file is subsequently processed bypython-docx, which can add further memory and CPU consumption.This is an insecure resource-management flaw in code that processes attacker-supplied archives.
Attack Path
- An attacker creates a syntactically valid DOCX archive containing many media members or highly compressible, very large content under
word/media/. - The attacker provides the DOCX to a user or service that invokes this Skill.
- The converter enumerates every matching member without enforcing size or count limits.
zip_ref.extract()decompresses all selected members into the output directory.- Disk, CP ...[truncated 480 chars]
- Remediation
View remediation
Remediation Suggestions
- Inspect each
ZipInfoentry before extraction and enforce a conservative maximum uncompressed size per member. - Enforce limits on the total number of media members and their cumulative uncompressed size.
- Reject entries whose compression ratio exceeds a safe threshold.
- Stream each file in bounded chunks rather than using unrestricted
ZipFile.extract(). - Abort extraction cleanly when any configured limit is exceeded and delete partial output.
- Apply process-level CPU, memory, execution-time, and disk quotas when handling untrusted documents.
- Validate that the input is a supported DOCX package before performing expensive processing.
- Inspect each
