flawopen.com/Teardowns/cve-2026-84973-jupyterlab-snapshot-checkout-toctou
CVE-2026-84973:JupyterLab 快照工作流 TOCTOU 漏洞
精度为一秒的时间检查可能让快照工作流检出并执行未经批准的 Pull Request 提交,且使用作业权限。请将 update-snapshots-checkout 升级至 1.0.0 或更高版本。
审查者批准了一个特定包裹,但收件处只核对时钟显示的秒数。如果有人在同一秒替换包裹,替换品也会被当成已批准。该 action 使用一秒精度的时间戳并允许相等值,因此 Pull Request 更新可能与维护者评论同时通过检查。
核心概念与专有名词
TOCTOU- Time-of-check to time-of-use:安全检查针对某个资源作出决定,但资源在实际使用前发生了变化。
Pull Request head SHA- Pull Request 分支顶端提交的不可变标识。工作流应只执行被明确授权的那个提交。
GitHub Actions 令牌权限- 作业的 GITHUB_TOKEN 被允许执行的仓库操作,例如读取或写入内容和 Pull Request。
CWE-367 / CWE-829- 公告将时间竞争归为
CWE-367,将执行由 Pull Request 控制的功能归为CWE-829。
框架映射
根本原因剖析 (Root Cause)
在 1.0.0 之前,update-snapshots-checkout 获取 Pull Request 的 pushed_at 与触发评论的 created_at,将二者转换为 Unix 秒,并且仅在 pushed_at 严格大于时拒绝运行。两个 API 时间戳的精度都是一秒,因此同一秒内的推送和授权评论可能得到相等值并通过检查。随后 action 保存当前 head SHA 并在 checkout 后核对;这只能证明检出的提交等于刚获取的 SHA,不能证明维护者授权了该提交。上游修复将 -gt 改为 -ge,从而拒绝相等和更晚的推送。只有使用受影响版本且后续步骤会执行 Pull Request 内容的工作流才面临风险;影响范围取决于工作流权限和凭据。
攻击执行流程分解
可信维护者触发工作流
Pull Request 创建后,OWNER、COLLABORATOR 或 MEMBER 发布评论,启动快照更新工作流。
攻击者控制的更新与评论发生在同一秒
贡献者在同一秒更新 Pull Request 分支。API 只有一秒精度,因此转换后的 Unix 秒数可能相等。
严格大于比较放过相等值
有漏洞的 action 仅在 pushed_at 大于 created_at 时拒绝。相等值不满足条件,因此新的 head SHA 被记录。
工作流检出该提交并可能执行它
checkout 与记录的 SHA 相符,因此通过后续校验。如果之后的步骤运行 Pull Request 控制的 action 或脚本,它们会使用作业配置的权限和凭据。
升级并降低工作流权限
升级到 1.0.0 或更高版本。将 actions 固定到不可变 SHA,只授予 GITHUB_TOKEN 必需权限,并避免在特权作业中执行不可信 Pull Request 代码。
源代码对比:漏洞与安全实现
这是上游的一行修复:在 API 的时间精度下,-ge 会拒绝相等值,从而关闭已记录的同秒绕过。仍应将授权绑定到不可变 SHA 并缩减权限;时间先后关系不能替代不可变的授权决策。 上游 diff 保留原有诊断消息;消息写的是“之后”,但现在相等值也会被拒绝。
if [[ $(date -d "$pushed_at" +%s) -gt $(date -d "$COMMENT_AT" +%s) ]]; then
echo "Updating is not allowed because the PR was pushed to (at $pushed_at) after the triggering comment was issued (at $COMMENT_AT)"
exit 1
fi
if [[ $(date -d "$pushed_at" +%s) -ge $(date -d "$COMMENT_AT" +%s) ]]; then
echo "Updating is not allowed because the PR was pushed to (at $pushed_at) after the triggering comment was issued (at $COMMENT_AT)"
exit 1
fi
工程与系统安全加固清单
- ✓将所有 update-snapshots-checkout 用法升级到 1.0.0 或更高版本,并检查复制或派生的代码。
- ✓将 actions 固定到经过审查的不可变 SHA,更新前审查对应变更。
- ✓不要只依赖时间戳授权可变的 Pull Request 分支;将批准绑定到确切 head SHA,SHA 变化时失败关闭。
- ✓为每个作业显式设置最小权限;不需要时不要授予 contents: write 或 pull-requests: write。
- ✓不要向执行外部 Pull Request 代码的作业提供机密或高权限部署凭据。
- ✓添加回归测试,确认相同和更晚的时间戳都会被拒绝。