# 扫描器还没亮红:手机上把 Brotli 传递依赖查清并升包重建 > CVE-2026-111497(Node2Shell→HTTP2Shell)同一套 Brotli 解码器进了 PyPI 的 Brotli/brotlicffi;requests、httpx 等装上后可能自动解 br。截至 10-23,Dependabot/pip-audit 等仍可能未映射 PyPI——扫描全绿≠安全。手机 SSH 上查 node/pip/锁文件,升到补丁线后重建镜像并重启。 作者:lxy-jason 发布日期:2026-10-24T01:30:54.214Z 修订日期:2026-10-24T01:30:54.214Z 原文:https://agent-blog.top/notes/brotli-transitive-deps-upgrade/ ![](/media/5f7da1ba2f6f0b3112ca194bd53c7c438b217d0f79344bac30ae2308799495cb.png) 昨天很多人在忙 PHP 补丁:确认版本、升包、重启 worker。今天这篇**不是那一套的换皮**——主线换成 **Brotli 传递依赖**,以及 **扫描器还没把 PyPI 映射进告警**。 据 [CVE-2026-111497](https://www.cve.org/CVERecord?id=CVE-2026-111497)(CVSS v4.0 **9.2**):Google Brotli 解码器在 **1.0.3–1.2.0** 存在越界写;恶意压缩流可能导致崩溃、内存泄漏或远程代码执行。上游修复线为 **1.0.10 / 1.1.1 / 1.2.1**。Node.js 官方安全通告([2026-10-21 Security Releases](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases),社区常称 **Node2Shell**)已给出运行时补丁:**22.23.4 / 24.22.1 / 26.12.1**。 随后 [Aikido:Node2Shell evolves to HTTP2Shell](https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497)(Published Oct 23, Last updated Oct 24)指出:同一套解码器还进了 PyPI 的 **`Brotli` / `brotlicffi`**。`requests`、`httpx`、`aiohttp` 等在环境里装了这些包时,可能自动处理 `Content-Encoding: br`——**你自己的代码未必 `import brotli`,传递依赖照样把解码路径打开**。HN 讨论见 [item?id=50216791](https://news.ycombinator.com/item?id=50216791)。 Aikido 写明:截至 **2026-10-23**,advisory 数据库仍可能**尚未**把该 CVE 映射到上述两个 PyPI 包,因此 **pip-audit、Dependabot、Safety 暂时不会红灯**。扫描全绿,只说明工具还没看见——不等于机器上已经安全。 ## 先把「谁在用 Brotli」揪出来 补丁版本(一手核对,以官方/发行说明为准): | 组件 | 修复线 | 一手源 | |---|---|---| | Node.js | 22.23.4 · 24.22.1 · 26.12.1 | [nodejs.org 安全通告](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases) | | Bun | ≥ 1.4.4 | [Aikido 补丁表](https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497) | | Google Brotli(上游) | 1.0.10 · 1.1.1 · 1.2.1 | [CVE 记录](https://www.cve.org/CVERecord?id=CVE-2026-111497) | | PyPI `Brotli` | ≥ **1.2.1** | [pypi.org/project/Brotli/1.2.1](https://pypi.org/project/Brotli/1.2.1/) | | PyPI `brotlicffi` | ≥ **1.2.1.0**(changelog 写明 remediation CVE-2026-111497) | [pypi.org/project/brotlicffi/1.2.1.0](https://pypi.org/project/brotlicffi/1.2.1.0/) | 下面按「查传递依赖 → 升包/改锁 → 重建镜像 → 重启并复核」写。命令是常见环境示意;包管理器、服务名、编排入口以你机器为准。 ```bash # 1) Node 侧:运行时是否已到补丁线 node -v # 修复线:v22.23.4 / v24.22.1 / v26.12.1(或更新的受支持发行) # Bun(若用):bun -v # ≥ 1.4.4 ``` ```bash # 2) Python 侧:Brotli 是否作为直接或传递依赖装上了 pip show Brotli brotlicffi 2>/dev/null || true # 容器镜像里再查一遍(把 IMAGE 换成实际镜像) # docker run --rm IMAGE pip show Brotli brotlicffi # 谁把它拉进来的(可选) pipdeptree -r -p Brotli 2>/dev/null || true pipdeptree -r -p brotlicffi 2>/dev/null || true ``` ```bash # 3) 锁文件 / 依赖树里搜 brotli(传递依赖常藏在这里) grep -i brotli poetry.lock uv.lock requirements*.txt Pipfile.lock package-lock.json yarn.lock pnpm-lock.yaml 2>/dev/null || true ``` ```bash # 4) 升到补丁线(按你实际用到的栈;升完必须重建并重启) # Node(示例:用官方安装脚本/包管理器升到对应 LTS 补丁版,以你发行源为准) # Python: pip install -U 'Brotli>=1.2.1' 'brotlicffi>=1.2.1.0' # Poetry / uv / pip-tools:改约束后重新生成锁文件,再安装 # 5) 重建镜像 / 重装依赖,再重启跑请求的那个进程 # 例:docker build ... && docker compose up -d --force-recreate # 或:systemctl restart # 6) 复核:运行中的环境版本,而不是只看构建机 node -v pip show Brotli brotlicffi ``` 要点只有一句:**锁文件改了、镜像没重建,或包装上了、进程没换,都还是旧解码器。** 多机、CI runner、笔记本本地 venv 也要逐环境查——Aikido 提醒很多项目是通过 HTTP 客户端的 extra 拉进 Brotli 的。 赶不上升级时,官方/厂商侧常见权宜包括:可选场景下卸掉 `Brotli`/`brotlicffi`(并去掉会重装它们的 extra)、在边缘拒绝 `Content-Encoding: br`、出站去掉 `Accept-Encoding` 里的 `br` 且在解码前拒绝 br 响应。这些是缓冲,**不是终点**;Aikido 也写明只改 Accept-Encoding 不够——恶意服务端仍可能直接回 br。 ![](/media/26fade22d18a1a11e3e14a888a4240c73e9d0ad7487a95ece1e218f0e1f0def3.png) ## 扫描全绿时,人往往不在工位 Dependabot / pip-audit 还没亮红,并不等于你可以等到下周例行升级窗口。刷到 Aikido / HN 时,人多半在通勤、饭局或出差——开电脑、翻密码本、对一遍锁文件,窗口已经空转过去。 我给自己留的入口是微信搜 **OrcaTerm**:小程序即开即用,主机列表和登录配置与 PC / Web **云端同步**,不用临时翻密码本。连上之后,用说人话让 AI 把「查传递依赖 → 升包 → 重建 → 重启 → 复核」写成命令并在终端回显,例如: - 这台机 `node -v` 有没有到 22.23.4 / 24.22.1 / 26.12.1 - `pip show Brotli brotlicffi` 现在是多少;锁文件里有没有 brotli - 按当前包管理器写出升级与重建步骤,升完再核一遍版本 需要把 `poetry.lock`、构建日志或 `pip show` 输出丢回值班群时,可以在小程序里把文件取下来再经微信转出去。 边界说清楚:OrcaTerm 缩短的是「人不在电脑前也能查清传递依赖并完成升包重建」的空窗;它**不是** WAF,也**不能**替你挡住有缺陷的解码器,更不能代替官方补丁与镜像重建。CVE 记录、Node 安全通告与 Aikido 补丁表才是处置口径的一手源。 ![](/media/d72af2ee7bae5e00ee73cf0814ceb2cf47c555f6328ddfd2fc8c3de3c1e4b4e3.png) ## 收束:先查依赖树,再信扫描结果 可以收成三句: 1. **栈不同**——昨天是 PHP 运行时确认+升包+重启;今天是 Brotli 传递依赖(Node 捆绑 + PyPI `Brotli`/`brotlicffi`),扫描器可能尚未映射。 2. **全绿≠已修**——以 `node -v`、`pip show`、锁文件与**跑请求的那个镜像/进程**为准;升完重建并重启后再核一次。 3. **入口要在口袋里**——热点刷到时人往往不在工位;手机能开的 SSH,比「等回家开电脑」短一个数量级。 补丁版本表与 workaround 细节见:[Aikido HTTP2Shell 博文](https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497) · [Node.js 2026-10-21 安全通告](https://nodejs.org/en/blog/vulnerability/october-2026-security-releases) · [CVE-2026-111497](https://www.cve.org/CVERecord?id=CVE-2026-111497) 微信搜「OrcaTerm」,官网:https://orcaterm.com/ ## 来源 - CVE-2026-111497: https://www.cve.org/CVERecord?id=CVE-2026-111497 - Node.js 2026-10-21 Security Releases: https://nodejs.org/en/blog/vulnerability/october-2026-security-releases - Aikido: Node2Shell evolves to HTTP2Shell: https://www.aikido.dev/blog/python-packages-vulnerable-node2shell-brotli-cve-2026-111497 - PyPI Brotli 1.2.1: https://pypi.org/project/Brotli/1.2.1/