# 威胁模型 — CVE-2026-111497（Brotli 解码器越界写入）

本文界定该工具认为哪些情形处于暴露状态、明确不覆盖哪些情形，以及为何把分类边界画在此处。
它是解读脚本返回的每一条判定的依据。

## 1. 漏洞

| 属性 | 值 |
|---|---|
| 标识 | CVE-2026-111497 |
| 组件 | Google Brotli，解码器（`c/dec/decode.c`） |
| 弱点 | CWE-787，越界写入 |
| 受影响的上游版本 | 1.0.3 … 1.0.9、1.1.0、1.2.0 |
| 已修复的上游版本 | 1.0.10、1.1.1、1.2.1（2026 年 10 月 21 日） |
| 攻击向量 | 将精心构造的 Brotli 流交给解码器处理 |
| 是否需要认证 | 否 |
| 影响 | 进程崩溃、内存破坏，在某些配置下可远程执行代码 |
| 严重性 | 项目公布的 CVSS 4.0 为 9.2；在发行版跟踪器中按 CVSS 3.x 计为 8.5 |

缺陷路径是块切换处的解码器状态机：畸形流使内部计数器越过预期边界，解码器于是写到已分配的
输出缓冲区之外，而不是提前报告该流无效。上游修复在写入之前检测并报告无效流。

## 2. 暴露什么、不暴露什么

决定大多数判定的正是这条区分：

- **编码器**（nginx `ngx_brotli`、`mod_brotli`、静态资源流水线）压缩的是服务器自身产生的数据。
  它从不解析攻击者可控的 Brotli。尽管它链接同一个软件包，它并非攻击面。
- **解码器**接受外部数据并解析它。那才是攻击面。

| 路径 | 何时暴露 | 说明 |
|---|---|---|
| HTTP 请求体 | 应用或代理解压 `Content-Encoding: br` | 在存在该路径时影响最大 |
| 出站 HTTP 客户端 | libcurl 的 `CURLOPT_ENCODING` 为空、Node `fetch`、带 Brotli 的 Python `httpx`/`requests` | 恶意或被攻陷的第三方以 `br` 作答 |
| 经代理的响应链 | 启用 Envoy/Istio HTTP 解压器 | 代理本身成为解码器 |
| 文件上传或导入 | 应用解压 Brotli 归档或流 | 审计中常被忽略 |
| 内置运行时 | Node.js、Bun、.NET 请求解压 | 修复随运行时到来，而非随 `libbrotli1` |

## 3. 为什么 libcurl 在真实机群中占主导

在三台生产主机上测得：可达的向量从来不是「发往 Web 服务器的请求」，因为 nginx 与 Apache
只用 Brotli 做压缩，都不解码请求体。占主导的路径是**经 libcurl 的出站 HTTP**，由 PHP 应用
代码触达。

把 `CURLOPT_ENCODING` 设为空字符串，等于让 libcurl 通告并接受它所支持的一切编码，包括 `br`。
这一个参数出现在：

- WordPress `wp-includes/Requests/src/Transport/Curl.php`；
- WordPress SimplePie `File.php`；
- 插件内附带的 Guzzle handler 工厂；
- 直接的 `wp_remote_*` 流量、RSS 抓取与第三方 API 调用。

在某台主机上，清单统计到 164 个携带 `CURLOPT_ENCODING` 或 `CURLOPT_ACCEPT_ENCODING` 的 PHP
文件。这个数字才是共享主机上暴露程度的真实度量 —— 而不是仅仅存在该软件包。

## 4. 攻击者模型

| 攻击者位置 | 能力 | 后果 |
|---|---|---|
| 远程、未认证 | 发送精心构造的 Brotli 请求体，或提供精心构造的 `br` 响应 | 崩溃、内存破坏，解码进程中可能执行代码 |
| 第三方内容提供方 | 控制服务器所抓取的端点 | 无需触及周界即可到达 libcurl 解码路径 |
| 本地非特权 | 提供应用要解压的文件 | 同一个解码器，影响较低 |

该工具假设攻击者可以选择字节，但无法选择进程：审计的目标是确保没有任何可达的解码器仍留在
存有漏洞的进程中。

## 5. 检测策略

软件包的存在不等于暴露。因此检测器记录四项相互独立的事实，只有在四项全部已知之后才做分类：

1. 已安装版本，剥离 epoch 与发行版修订号，还原为上游版本号；
2. 打包的变更日志是否已引用该 CVE（即发行版回溯移植已应用）；
3. apt 候选版本是否比已安装版本更新（即存在受支持的修复）；
4. 哪些正在运行的进程映射了 `libbrotlidec`，以及经由哪个运行时。

只有当上游版本位于受影响范围**并且**没有回溯移植时，主机才被判为 `VULNERABLE`。任一条件
不成立即为 `SAFE` —— 包括发行版修订号仍保留看似受影响的上游版本号、但已携带修复的情形。

## 6. 范围之外

| 领域 | 原因 |
|---|---|
| 静态链接的副本 | 对 `dpkg` 不可见；需要逐文件扫描二进制 |
| 容器镜像 | 需要仓库侧扫描，而非主机侧检查 |
| Envoy、Istio、.NET、Bun、Deno | 修复生命周期各自独立；仅作文档说明，不做自动化 |
| Windows 与 macOS 主机 | 该工具仅支持 bash 与 apt |
| 应用层缓解 | 阻断 `Content-Encoding: br` 是运维人员采用的权宜手段，不是修复 |

## 7. 修复后的残余风险

1. 桌面与基础设施进程会继续映射旧库，直到下次登录或重启。它们不属于服务器解码路径；
   检测器将其报告为 `deferred`。
2. 在修复**之后**、库被替换**之前**所安装的软件包启动的进程，会继承已打补丁的库 ——
   `remediate.sh` 内部的执行顺序正是为防止相反情形。
3. 应用代码若自带 Brotli（内置源码、静态构建），不受软件包更新的影响，必须单独重建。

流程见 [PLAYBOOK.zh.md](PLAYBOOK.zh.md)，这三项事实在真实主机上的具体样貌见
[FIELD-REPORT.zh.md](FIELD-REPORT.zh.md)。
