CVE-2026-44431 · urllib3 2.6.3 → 2.7.0 · 复现于 2026 年 9 月 27 日
一个请求携带三个敏感头信息发往某个源。一次重定向改变了目标地址。下一个请求是否仍然携带它们?
这个独立的回归测试运行了来自两个确切 urllib3 版本的真实重定向实现。版本 2.6.3 在受影响的底层 API 中保留了全部三个头信息。版本 2.7.0 移除了它们。一个无害的头信息得以保留,普通请求仍然正常工作。
| 测试用例 | urllib3 2.6.3 | urllib3 2.7.0 |
|---|---|---|
| 底层跨源重定向 | 保留 3 个敏感头信息 | 保留 0 个 |
| 使用小写名称的相同用例 | 保留 3 个 | 保留 0 个 |
| 高层 API 对照 | 保留 0 个 | 保留 0 个 |
| 直接 200 响应 | 按预期保留 3 个 | 按预期保留 3 个 |
| 显式禁用重定向 | 一次调用;返回 302 | 一次调用;返回 302 |
| 自定义移除集添加无害标记 | 保留全部 4 个头信息 | 移除全部 4 个 |
12/12 场景预期通过。 每个场景还检查响应状态、传输调用次数、初始头信息集、无害头信息结果,以及调用方的头信息未被修改。漏洞结果是预期的基线结果,而非通过的安全检查。
机器可读结果 包含捕获的参数、确切的 wheel 哈希、运行时、测试源码哈希、归属信息以及复现时间。
上游安全公告 发布于 2026 年 5 月 7 日,指出了 urllib3 代理底层重定向路径中的信息暴露问题。它将版本 >=1.23, <2.7.0 列为受影响版本。调用 ProxyManager.connection_from_url(...).urlopen(..., assert_same_host=False) 可能会将配置的敏感头信息带入到发往另一个源的重定向请求中。高层管理器 API 已经移除了它们。
上游修复 在递归底层请求之前应用了 Retry.remove_headers_on_redirect。我们的头信息小写用例遵循了上游回归测试对头信息名称大小写的关注。自定义移除用例检查该规则是否遵循配置的集合,而不仅仅是三个默认名称。
该安全公告将 christos-cantina-security 列为报告者,illia-v 列为协调者,sethmlarson 列为修复审查者。Sergio Rodriguez 在此处的贡献是独立的离线测试框架和前后对比分析。这是对他们已发布的 CVE 的复现。
使用 Python 3.10 或更高版本。无需 pip install 或虚拟环境:每个版本都直接从其纯 Python wheel 在全新的隔离子进程中导入。
从组合仓库根目录运行:
python -B ./labs/cve-replay/run_replay.py --fetch
python -B ./labs/cve-replay/run_replay.py
第一条命令将两个确切的 wheel 下载到实验室被忽略的 .cache/wheels/ 目录中,并根据清单检查它们的 SHA-256 哈希。第二条命令使用该缓存而不下载。对于独立的源码检出,运行 python -B run_replay.py --fetch,然后运行不带 --fetch 的相同命令。--cache 接受不同的本地缓存目录。
HTTPConnectionPool._make_request 被替换为双响应传输:一个带有固定 location 的 302,然后是一个 200。测试用例捕获到达该边界的参数。urllib3 的解析、重试策略、头信息过滤和递归重定向处理从所选 wheel 原样执行。
所有目标地址都是固定的保留 .invalid 名称;所有头信息值都以 DUMMY 开头。套接字构造和 DNS 函数会立即抛出异常。库在导入时的 IPv6 能力探测被拒绝并单独记录;重放场景不尝试任何网络操作。没有监听服务器或实时目标。
这验证了重定向参数处理。它不测量端到端代理流量。版本 2.7.0 是针对此特定 CVE 的第一个修复版本;此历史比较并非建议选择它而非更新的受支持版本。
测试脚本和分析是原创的组合作品。urllib3 是一个上游项目,根据其 MIT 许可证 分发;其代码和发布 wheel 未在组合源码归档中重新分发。它们从 PyPI 单独下载,并为实验原样导入。