编程 jq 1.8.2 一次修了 16 个 CVE:把不可信 JSON 喂给 jq 的代价

2026-10-26 21:05:10

jq 1.8.2 一次修了 16 个 CVE:把不可信 JSON 喂给 jq 的代价

jq 在流水线里的实际位置

curl ... | jq、日志按行切片、校验用户上传的 JSON,这些用法中 jq 解析的往往是外部输入。这类组件的缺陷不只表现为"输出错了",还可能造成崩溃、越界读写和拒绝服务,而且发生在 set -e 的脚本中间时,失败点很难定位。

2026-06-20 发布的 jq 1.8.2 一次性修了 16 个 CVE,外加两个 GHSA 编号问题,还有一批未编号的加固。下面按触发方式分组,同类问题合并说明。

栈溢出与递归深度

共同点:数据结构的深度由输入决定,而递归实现没有深度上限。

  • CVE-2026-33947:给 jv_setpath / jv_getpath / jv_delpaths 的路径深度加限制
  • CVE-2026-40612:contains 的包含检查加深度限制
  • CVE-2026-43896:递归对象 merge 加深度限制
  • CVE-2026-44777:检测循环模块 import
  • CVE-2026-47770:深层结构相等比较与比较递归加防护
  • 未编号项:释放深层嵌套值时避免栈溢出

触发这些缺陷不需要恶意构造,一个几万层嵌套的数组就足够让 jq 发生段错误。contains 和 == 这类看似无害的运算符尤其容易被忽略,因为调用方通常只把它们当成判断语句。

内存与溢出

  • CVE-2026-32316:jvp_string_append 与 jvp_string_copy_replace_bad 堆缓冲区溢出
  • CVE-2026-39979:jv_parse_sized() 越界读
  • CVE-2026-49839:raw file 加载时堆溢出
  • GHSA-hj52-j2c9-r8r4:tokenadd 有符号整数溢出(同类的 CVE-2026-41257 是 stack_reallocate 的符号溢出)

这类问题在 ASan 构建下是稳定可复现的崩溃,在普通构建里可能表现为静默的内存破坏。--rawfile 这条值得单独记:它读的不是 JSON,而是整份原始文件,长度完全由被读文件决定,所以不要把不可信路径交给它。

解析语义

  • CVE-2026-33948:JSON parser 的 NUL 截断
  • CVE-2026-41256:用 -f 加载的程序文件 NUL 截断
  • CVE-2026-43894:拒绝长于 DEC_MAX_DIGITS(999999999)的数字字面量
  • CVE-2026-43895:模块 import 路径中嵌入 NUL 字节被拒
  • CVE-2026-39956:_strindices 缺少运行时类型检查
  • CVE-2026-54679:收紧字符串长度边界,implode 传播非法 jv
  • GHSA-gf4g-95wj-4q4r:args2obj() 数组参数路径的 use-after-free

NUL 截断的后果是校验位置看到的内容和处理位置看到的内容不一致:解析器读到 \0 就当字符串结束,后面的字节被丢掉。对做白名单/黑名单校验的脚本,这等于让校验结果失真。

DoS

  • CVE-2026-40164:随机化 hash seed,缓解哈希碰撞型 DoS
  • 函数参数个数与函数定义数量加上限,避免 SEGV

另外,1.8.2 预分配了字符串解析用的 tokenbuf,修了若干内存泄漏与双重释放。这些没有 CVE 编号,但对常驻服务来说比一次崩溃更隐蔽。

停在 1.8.0 并不等于安全

2025-07 的 1.8.1 修了 CVE-2025-49014(f_strftime 堆 use-after-free),但把 1.8.0 引入的 reduce/foreach 状态变量改动回退了,原因是严重的性能回退。也就是说 1.8.0 有已知漏洞,1.8.1 在不同行为上有一次退让,1.8.2 才是把这一批安全修复叠上去的版本。

可以立刻做的几件事

升级到 1.8.2,然后在流水线入口限制输入规模与耗时:

curl -s "$API" | head -c 10485760 | jq -r '.data[]'
timeout 10 jq -e '.ok' input.json

给 jq 进程加栈和虚拟内存上限,把爆栈变成可预期的失败而不是整机抖动:

( ulimit -s 8192; ulimit -v 1048576; jq . untrusted.json )

需要限制嵌套深度时,先量一遍再决定是否放行(paths 在大文件上有开销):

jq -e '[paths] | map(length) | max
复制全文 生成海报 Shell 安全 jq 运维

推荐文章

程序员茄子在线接单