FlawOpen

flawopen.com/目录/226

● CWE-367 / CWE-829 · 高危
安全研究 · FlawOpen

Marimo GHSL-2026-226:测试发布工作流中的 TOCTOU

同一秒内的时间戳竞争可使 Pull Request 更新绕过维护者的测试发布批准,并进入 TestPyPI 和 npm 发布作业。易受攻击的工作流已删除;未分配 CVE。

💡 通俗易懂的原理解析 (ELI5)

实验室负责人批准了一个样本,但实验室只核对时钟上的秒数。如果有人在同一秒更换样本,替换品也会被误认为已批准。Marimo 工作流对 Pull Request 提交犯了同样的错误,随后把构建出的包交给发布作业。

核心概念与专有名词

TOCTOU
Time-of-check to time-of-use:资源在安全检查后、实际使用前发生变化。
OIDC 发布
CI 作业将 GitHub Actions 身份换成包注册表的短期凭据,而不保存长期密码。
工作流工件
在 GitHub Actions 作业间传递的文件集合。下游作业应将不可信工作流生成的工件视为不可信输入。
GHSL-2026-226
GitHub Security Lab 对此 Marimo 工作流缺陷的公告编号。该公告未分配 CVE。
CWE-367 / CWE-829
公告指出了检查与使用之间的时间竞争,以及执行不可信控制域中的功能。

框架映射

攻击执行流程分解

步骤 1

维护者批准测试发布

维护者在 Pull Request 中发表评论,启动 Marimo 测试发布工作流。批准本应仅适用于维护者审查过的 Pull Request 状态。

步骤 2

Pull Request head 在同一秒发生变化

工作流将仓库的 pushed_at 与评论的 created_at 转换为整秒后进行比较。同一秒的 push 会得到相等值。

步骤 3

有漏洞的检查接受相等值

已删除的工作流只拒绝严格晚于评论时间的 pushed_at。相等值通过检查,更新后的提交被记录。

步骤 4

不可信代码构建软件包工件

作业检出该提交并运行由仓库控制的 actions 和构建脚本。生成物被上传为工件,随后交给下游发布作业,且没有从可信提交重新构建。

步骤 5

发布权限触及不可信输出

TestPyPI 和 npm 作业使用 OIDC 发布权限。公告说明工件可能进入发布流程;它没有报告实际软件包遭到入侵。

源代码对比:漏洞与安全实现

GHSL-2026-226 说明易受攻击的工作流已在 PR #10765 中删除;这并不表示项目应用了此处展示的比较符修改。旧检查使用 -gt,因此整秒相等值会通过。此处的 -ge 示例会拒绝相等值,但更好的做法是将批准绑定到准确的已审查提交。将不可信构建与 OIDC 作业分开,从获批 SHA 重新构建,并在发布前验证来源。本文不包含利用载荷。

存在漏洞的实现
# 已删除的 marimo-bot 工作流:整秒比较
if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
    exit 1
fi
# 记录的 head_sha 随后被检出,工件被交给
# 独立的发布作业。
加固后的安全修复
# 仅为说明性控制;GHSL 指出易受攻击的工作流
# 已删除,而不是在原处修补。
if [[ $(date -d "$pushed_at" +%s) -ge $(date -d "$COMMENT_AT" +%s) ]]; then
    exit 1
fi
# 更强的设计:授权经过审查的不可变 SHA,在可信作业
# 中从该 SHA 重建,再发布经过验证的输出。

工程与系统安全加固清单

参考来源