BabelDOC 发布了新版本,将 PDF 处理流程迁移至 Rust,并为读取文档时的资源使用设置默认上限。翻译外部 PDF 的服务可借此降低小型恶意文件大量占用内存、导致任务停止的风险。
1. 将 PDF 读取与重写流程迁移至 Rust
本版本不仅在 Rust 中执行 PDF 解析,还涵盖扫描文档识别、图文布局、段落与样式处理、翻译协调、将页面元素安排为印刷形式的排版,以及 PDF 写入。布局模型、用于确定文档元素位置的模型及翻译服务集成仍保留在 Python 中,Python 也继续作为使用入口。
据项目公告,PDF 读取速度较 0.6.4 更快,内存用量也有所降低。目标是让默认处理路径的文档输出与旧版本保持一致,预期变化则是水印调整和新增资源上限。
2. 阻断小型输入耗尽内存的路径
0.7.0 默认启用资源上限,以防读取输入 PDF 时资源用量过度增长。超限时会停止处理,并抛出包含被触发限制的名称、数值及发生位置的异常。可以一次性关闭所有限制,但此时会记录警告。
第一份安全公告涉及解压 PDF 数据时未限制输出大小、从而耗尽内存的问题。这就像打开压缩包后,小包裹膨胀成了巨大的货物。
根据公告中的复现记录,Python 3.11 精简容器内的 BabelDOC 0.6.4 将 1,043,644 字节解压为 1,073,741,824 字节。解压耗时 2.70 秒,进程峰值内存从 1,068,544KiB 增至 2,116,024KiB。
复现的部分核心代码如下。
stream = PDFStream(attrs={"Filter": LIT("FlateDecode")}, rawdata=payload)
mem_before = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
print(f"\nProcess RSS before decode(): {mem_before} KiB")
start = time.time()
stream.decode() # <-- the real, unmodified vulnerable call: zlib.decompress(data), no max size
elapsed = time.time() - start第二份公告涉及将字体字符代码映射到实际字符的 ToUnicode 映射问题。逐一展开并存储字符代码范围会消耗资源。在 BabelDOC 0.6.4 中,将相同输入传给原有 Python 解析器及后续 Python 解析器的复现记录如下。
表:ToUnicode 范围展开复现结果
条件:BabelDOC 0.6.4,Docker 内的 Python,断网,直接以输入字节调用解析器(2026年10月16日运行结果)
单位:时间为秒,条目数为个
| 解析器·范围终值 | 时间 | 条目数 |
|---|---|---|
| 原有 Python 解析器·000000FF | 0.0004 | — |
| 原有 Python 解析器·000FFFFF | 0.41 | — |
| 原有 Python 解析器·00FFFFFF | 6.72 | — |
| 后续 Python 解析器·000000FF | 0.0 | 256 |
| 后续 Python 解析器·000FFFFF | 0.54 | 1048576 |
| 后续 Python 解析器·00FFFFFF | 18.44 | 16777216 |
表中范围均从 00000000 开始。在同一解析器中扩大范围后,处理时间随之增加。另一次在 1GiB 内存限制下展开 00000000~FFFFFFFF 范围的测试以退出码 137 被强制终止。新 Rust 解析器以区间而非单个条目存储范围,并对保留的映射数据施加默认上限。
3. 安全改进的代价是超限文档处理失败
两份公告均将受影响版本标为 0.6.4 及以下,修复包含在 0.7.0 中。此次于 2026年11月7日发布的版本,以 Rust 实现替换了会引发资源放大、即输入处理过程中资源用量大幅增长的 Python 解析器实现。维护者表示,安全修复仅提供给最新版本,不会正式向旧版本回移修复,即将修复应用到旧版本。
资源上限降低了恶意输入过度占用内存的风险,但即使是正常文档,超限也会被拒绝翻译。服务运营者需要准备向用户说明失败原因的流程。对于必须处理的文档,项目介绍了关闭上限并施加外部限制的方法。
复现数值来自直接调用解析器,并非完整翻译流程或新 Rust 实现的性能测量结果。维护者建议,在处理不可信 PDF 时,同时为翻译进程设置时间限制和容器内存限制。
4. 使用预构建包,并用自有文档核验结果
预构建包是预先构建、可直接安装的软件包,面向 Linux x86-64、ARM64,Windows x86-64,以及 Mac Intel、Apple Silicon 五个平台提供。支持的 Python 版本为 3.10~3.13。在其他平台安装源码发行包,即包含源代码和构建配置的分发文件,或从仓库直接构建时,需要 Rust 工具链,也就是编译和构建所需的工具集合。
公开入口保持不变,但直接导入已删除内部 Python 模块的外部代码需要修改。维护者建议,在升级生产环境前,先用自有文档核验结果。
不再添加首页水印。相关设置仍被接受,但只会改变输出文件的名称和数量,因此核验结果时也需留意这一变化。
0.7.0 限制了 PDF 解析器中危险的资源放大路径,但也可能导致部分文档处理失败,因此升级的关键是事先准备好如何在运营中应对超限任务。
