2.2.17 安全审计复核与 2.2.18 修复记录¶
日期:2026-09-28。复核基线:2.2.17 / aa1746e。本次工作在独立分支进行,原有 2.3 开发工作区保持原状。
结论¶
同意报告识别出的主要信任边界缺口,尤其是导入元数据覆盖参数、实验包身份不一致、GPU 输出链接读取、桌面登录令牌和公共导出配额。2.2.18 针对这些问题加固,并加入负向回归测试与正常流程验证。
这次复核有以下修正和限定:
- “上传文件不能执行代码”应表述为:在已检查的正常路由、当前解析器和依赖版本中,没有确认匿名上传直接导致代码执行的路径。静态分析及进程内测试不能证明所有输入都安全。
- GPU 链需要先控制 VM、GPU 输入通道或容器。它是重要的隔离边界缺口;报告没有证明匿名租户能达到此前提,不能直接称为互联网匿名 RCE。宿主代理仍以 root 运行。
- 请求限速表
rate_limit()在 2.2.17 已经检查 key 是否存在;报告关于它“满后所有网络都被拒绝”的描述不准确。会话预算表admit()确实缺少此检查。 - 进程内
DAY = 86400,预算按 UTC 天清空;部署模板另有每 12 小时重启的 systemd timer。报告中的 12 小时上限依赖该 timer 正常执行,不能从进程内逻辑单独推出。后续发布检查确认生产 timer 已启用,按 11:59/23:59 UTC 执行。 - Virtual PA 的 metadata 接口本身没有重算 CSV;input metadata 和 CSV 导出路径的重复计算与共享锁问题成立。
- 分享包脱敏问题可在 Linux 上用 Windows 路径字符串复现;这不等于完成真实 Windows SMB/NTLM 或原生窗口测试。
- 清单与内容共同来自同一个包,SHA-256 只能验证它们之间的一致性。真实性仍需要可信来源或独立传递的哈希。
报告中的 12 项 Medium¶
| 发现 | 复核判断 | 2.2.18 的处理 |
|---|---|---|
| M1 / GPU-1 | 成立,前提是容器或 VM 已失陷 | 最终打包从可信工作目录 fd 逐级打开目录和普通文件,拒绝链接、特殊文件及硬链接;读取字节数、文件数和目录深度受限;移除容器后才收集结果。实时读取也从工作区根 fd 逐级打开 runs 和运行目录。 |
| M2 / GPU-2 | 成立,VM 提供的工作目录不应是 Python 模块来源 | 容器使用 -P、PYTHONSAFEPATH、工作目录 /;输入归档限制顶层结构和文件类型;CPU worker 也移除不安全的当前目录导入路径。 |
| M3 / EXE-1/2 | 成立 | LegacySpec 白名单和类型校验;hparams 与 Namespace 分离;CSV 名称、成员链接、输出目录组件均校验;未知训练参数在导入或加载时拒绝。 |
| M4 / ARC-2 | 成立 | 内外 manifest 的 ID、数据哈希和 source kind 必须一致;run/config/artifact schema 在导入前校验;私有快照、暂存和失败回滚;解压后再次核对 raw 哈希。 |
| M5 / ARC-3 | 成立 | 数据版本和 split version 使用标识符类型;完整导出检查版本路径包含性和链接。 |
| M6 / CON-1 | 成立 | 排行榜先检查包哈希、类型、身份,再导入;导入的私有快照再次检查外部记录的哈希及 share 类型;包路径必须是受限 ZIP 文件名。 |
| M7 / ENV-1 | 成立;运行收到的 Python 文件本身也意味着信任代码 | 新的 installed CLI 直接读取 ZIP/目录中的数据并检查成员完整性,不插入 bundle 的模块路径。直接脚本要求 safe-path 模式;--use-bundled-source 仍是显式执行第三方代码的选项,只应用于可信来源。 |
| M8 / WIN-1 | 成立 | 逐字符串递归脱敏 JSON;Windows 路径同时匹配两种分隔符并忽略大小写。 |
| M9 / WIN-3/4 | 路径校验缺口成立;NTLM 外传未在 Windows 实测 | 文件系统访问之前拒绝盘符、UNC、冒号、空段、./..、设备名和尾部点/空格;关键导出和读取点再检查包含性。 |
| M10 / LOC-1 | 成立,尤其是多用户 Linux | 一次性 120 秒 bootstrap;独立 launcher credential 支持重新打开;0600 原子锁文件和私有浏览器重定向文件;SSH/无图形环境默认只输出访问方式。 |
| M11 / WEB-2 | 主要结论成立,metadata 路径的描述需区分 | 补齐昂贵 GET 路由;按工作区共用可重入锁;不可变信号的 CSV 导出缓存;每个网络最多一个重负载请求。 |
| M12 / WEB-4 | 会话表缺陷成立;限速表描述需修正,12 小时上限依赖部署 timer | 容量提高到 65,536,仅拒绝尚未记录的新网络;IPv6 按 /48 聚合。有限容量仍可能被分布式攻击耗尽,边缘限流仍有必要。 |
同步纳入的较低等级加固¶
- NPZ/NPY 在分配前检查头部、dtype、shape、成员数量和总大小;拒绝非数组成员和 object dtype。
- 旧数据目录拒绝链接成员;
FileRef、实验包和导出复用可移植路径检查。 - Plotly 标签文本转义,导入图表结构和文本长度受限;i18n 对过长文本跳过模板正则。
- 比较表、图表 CSV 转义公式文本;排行榜 Markdown 转义用户文本。
- 补齐桌面 POST 的 CSRF 依赖并检查 API 的
Sec-Fetch-Site;POSIX 新工作区 0700,拒绝不可信所有权/写权限。 - 去掉 benchmark 的不受限
torch.load回退,并用 AST 回归扫描相关源码目录。 - JSON 读取完成后才预留重负载资源;同一网络最多六个在途请求。CSV 上传仍持有受限的上传/重负载槽位并有超时。
starlette>=1.3.1、h11>=0.16.0和文档依赖下限;CI 自动审计 VM/GPU 锁文件,扩大 CODEOWNERS。- protected-paths 辅助检查读取可信 base 分支代码,用 API 同时检查重命名前后文件名;独立的当前提交审批才计为通过。原生 ruleset 仍是主要合并控制。
- 前端验证文件移入仓库内忽略目录;复现源文件按 Git 跟踪列表或已安装发行版 RECORD 选择,排除偶然存在的未跟踪源码。
验证范围与剩余工作¶
同一组最小复现的前后对照¶
在 aa1746e 的原 2.2.17 和本分支分别运行相同探针,所有文件都是临时合成文件,未读取真实机密文件或连接线上服务。
| 探针 | 2.2.17 | 2.2.18 |
|---|---|---|
| spec 改写训练参数 | 可改写 | 拒绝,参数保持原值 |
| GPU 打包跟随被替换的运行根目录 | 可读取外部合成标记 | 拒绝 |
| Windows 路径字符串泄露 | 泄露 | 已脱敏 |
| bootstrap 再次兑换 | 可重复 | 拒绝 |
| preprocessing version 中的目录穿越 | 接受 | 拒绝 |
| 输入 CSV 导出绕过重负载分类 | 未计入 | 计入 |
回归与范围¶
安全回归涉及路径、元数据、令牌、归档、输出链接、导出缓存和网络预算;正常回归涉及训练、实验导入导出、排行榜、图表重放、虚拟 PA 和安装后的桌面服务。最终测试数量记录在发布验证记录中:普通 Python 回归覆盖 2,285 项,前端 282 项,安装包验证 3 项。另在真实 Chromium 中验证了私有文件登录跳转和一次性令牌。
初次补丁复核限于本地验证。随后的发布暂存检查补充了 Windows/macOS 安装、安全边界用例、离线 VM 和真实 GPU 容器测试,详见发布验证记录。原生 pywebview 窗口尚未实测;以下问题仍需要独立的后续工作或运维证据:
- rootful GPU agent 的权限进一步拆分、VM worker 独立 UID、GPU 驱动/CDI/内核及镜像 OS 包审计;
BindsTo降低端口失联窗口,不能替代桥接端点认证。 - Cloudflare 请求体缓冲、WAF、响应头和独立 Studio 源;共享 IPv6 /48 的并发/预算需要结合真实用户规模调节。
- GitHub 的必需 Code Owner 审阅、tag/environment 保护、PyPI Trusted Publisher 和发布审计门禁的实际状态。
- Windows 文件 ACL、SMB 行为和原生窗口导航/pywebview 内部 bridge;纯 Python 和字符串测试不能替代平台验证。
- 旧版
run_in_directory的进程 cwd、源树内置数据目录中可执行 demodulator、原生发布确认、真实 RF interlock 取消语义;本补丁没有重构这些边界。 - 用户额外添加的共享导入根目录中,并发写入者仍可能在路径检查后替换文件;普通本地导入尚未全面改成 fd 贯穿读取。静态链接拒绝测试不能证明不存在这种竞态。
- 完整可复现构建、安装时 RECORD 校验、独立的数据集发布清单、隐私说明和数据保留政策。
参考:Python safe-path 参数(3.11 起提供;CPU worker 对 3.10 使用显式移除启动目录的兼容方式);GitHub pull_request_target 的信任边界。