![[Bug] Potential DoS via Unbounded zlib.decompress (Zip Bomb Vulnerability) in Document Parser](https://www.chat-gpts.plus/wp-content/uploads/2026/07/22101-643a5001.jpg)
[Bug] Potential DoS via Unbounded zlib.decompress (Zip Bomb Vulnerability) in Document Parser
快速结论:该报错发生在 LlamaIndex 的 HWP 文档解析器中,当读取恶意构造的高压缩比文档时,zlib.decompress(data, -15) 无大小限制的解压操作会瞬间耗尽内存,导致 OOM 崩溃。优先排查是否使用了受影响的 HWP Reader,并在代码中添加解压大小上限。
问题场景
用户在使用 LlamaIndex 的 HWP 文档解析器(llama-index-readers-hwp)读取 HWP 文件时触发问题。攻击者可以通过提供包含超高压缩比内容的恶意文档(Zip Bomb),在解析过程中导致服务端内存耗尽(OOM),造成拒绝服务(DoS)。该问题通过静态代码分析发现,在 base.py 的 get_text_from_section 方法中。
报错原文
unpacked_data = (
zlib.decompress(data, -15) if self.is_compressed(load_file) else data
)
# 实际运行时观察到的现象为:
# 内存瞬间飙升至全部可用内存,触发操作系统 OOM killer 杀死进程,无显式 Python 报错。
原因分析
zlib.decompress(data, -15) 调用在处理单个压缩块时,没有对解压后的数据大小设置任何限制,也没有检查压缩比或使用流式解压。攻击者可以构造一个体积很小的压缩文档,解压后膨胀数 GB,导致单次 zlib.decompress 调用直接分配巨大内存,引发 OOM 崩溃。这是一个经典的 Zip Bomb 漏洞。
环境排查
- 确认是否使用了
llama-index-readers-hwp集成包 - 定位代码位置:
llama-index-integrations/readers/llama-index-readers-hwp/llama_index/readers/hwp/base.py第 89–95 行
解决步骤
- 定位受影响代码:打开
base.py文件,找到get_text_from_section方法中的zlib.decompress(data, -15)调用。 - 添加安全解压函数(可优先尝试):在类中新增一个带最大解压大小限制的
_safe_decompress方法。示例实现如下:MAX_DECOMPRESSED_SIZE = 100 * 1024 * 1024 # 100 MB 限制,可根据需求调整 def _safe_decompress(self, data: bytes, max_size: int = MAX_DECOMPRESSED_SIZE) -> bytes: decompressor = zlib.decompressobj(-15) result = b"" chunk = decompressor.decompress(data, max_size) result += chunk if decompressor.unconsumed_tail or not decompressor.eof: if len(result) >= max_size: raise ValueError( f"Decompressed data exceeds maximum allowed size ({max_size} bytes). " "Possible decompression bomb." ) return result - 替换原始调用:将原始行替换为:
unpacked_data = ( self._safe_decompress(data) if self.is_compressed(load_file) else data )注意:使用
zlib.decompressobj+ 增量解压是推荐方案,但上述示例中decompress(data, max_size)仍可能一次性消耗大量内存。更安全的做法是分多次读取并累计大小检查。如果安全性要求更高,可参考以下流式方案:def _safe_decompress_stream(self, data: bytes, max_size: int = MAX_DECOMPRESSED_SIZE) -> bytes: decompressor = zlib.decompressobj(-15) result = b"" # 逐块处理,假设 data 已经全部加载到内存 chunk = decompressor.decompress(data, 8192) # 每次最多解压 8KB while chunk: result += chunk if len(result) > max_size: raise ValueError(...) chunk = decompressor.decompress(data, 8192) # 需要使用剩余数据,实际需用 unconsumed_tail return result注意:以上流式代码为示意,实际实现需要处理
unconsumed_tail,建议直接采用 Issue 中的_safe_decompress方案作为基线。
验证方法
构建一个压缩后很小(如 1KB)但解压后超过 200MB 的测试文件(可使用 python3 -c "import zlib; import sys; sys.stdout.buffer.write(zlib.compress(b'A'*300*1024*1024))" 生成),尝试用 HWP Reader 解析。如果代码抛出 ValueError: Decompressed data exceeds maximum allowed size,且程序未 OOM 崩溃,则修复生效。



