T09 · Insecure Skill Coding Practices
Warning
- Location
- read_file.py:76
- Finding
- Unbounded Office archive decompression can cause resource exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `read_file.py:76-107` **Vulnerable Operations**: `read_file.py:79`, `read_file.py:88`, and `read_file.py:102` **Vulnerability Type**: Uncontrolled resource consumption through ZIP decompression **Risk Level**: Medium ### Vulnerable Code ```python def read_docx(file_path): """读取 Word 文档 (.docx) 内容""" texts = [] with zipfile.ZipFile(file_path, 'r') as z: # 读取 document.xml content = z.read('word/document.xml') # 提取所有 w:t 标签中的文本 matches = re.findall(b'<w:t[^>]*>([^<]*)</w:t>', content) for match in matches: texts.append(match.decode('utf-8')) return '\n'.join(texts) def read_xlsx(file_path): """读取 Excel 表格 (.xlsx) 内容""" texts = [] with zipfile.ZipFile(file_path, 'r') as z: # 读取 sharedStrings.xml try: content = z.read('xl/sharedStrings.xml') # 提取所有 t 标签中的文本 matches = re.findall(b'<si><t>([^<]*)</t>', content) for match in matches: texts.append(match.decode('utf-8')) except KeyError: # 如果没有 sharedStrings.xml,尝试读取 worksheets for name in z.namelist(): if name.startswith('xl/worksheets/sheet') and name.endswith('.xml'): content = z.read(name) # 提取 cell 中的值 matches = re.findall(b'<v>([^<]*)</v>', content) for match in matches: try: texts.append(match.decode('utf-8')) except: pass return '\n'.join(texts) ``` ### Technical Analysis DOCX and XLSX documents are ZIP archives. The implementation calls `ZipFile.read()` on archive entries without validating the input file size, uncompressed entry size, cumulative uncompressed size, compression ratio, or number of worksheet entries. `ZipFile.read()` decompresses an ent ...[truncated 1998 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Reject input archives larger than a documented maximum before opening them. 2. Inspect every relevant `ZipInfo` entry before decompression and enforce: - A maximum number of archive entries. - A maximum uncompressed size per entry. - A maximum cumulative uncompressed size. - A maximum compression ratio, with safe handling for zero-byte compressed sizes. 3. Read entries incrementally with `ZipFile.open()` rather than using `ZipFile.read()`. 4. Parse Office XML with a streaming parser such as `xml.etree.ElementTree.iterparse()` and stop when a configured text or byte limit is reached. 5. Limit the amount of extracted text retained and written to standard output. 6. Catch `zipfile.BadZipFile`, size-limit violations, decompression errors, and decoding failures explicitly, then return a controlled error. 7. When this reader is exposed through an Agent or service, run it with memory, CPU, and execution-time limits in a sandboxed worker process. 8. Add regression tests using archives with extreme compression ratios, oversized XML entries, excessive worksheet counts, and excessive cumulative expanded size. ]]>
