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