2026 年 10 月 28 日,GitHub Actions 工作流锁文件(Workflow Lockfiles)正式全面可用,覆盖 GitHub Enterprise Cloud、Team 和 Free 计划。开发者只需安装命令行扩展 gh-actions-lock,就能把工作流配置里原本用来防供应链投毒的 40 位完整 SHA 还原成 v7.0.1 这样的清晰版本号,同时在仓库里自动生成一份 .github/workflows/actions.lock。很多开发者把它当成美化配置文件的语法糖,但这项更新真正的价值是把 CI/CD 依赖拉进了现代包管理器的治理框架,顺手补上了传统哈希固定法防不住的两个安全盲区。

在此之前,由于 Git 标签可以随时被篡改(例如曾引发广泛震动的 tj-actions/changed-files 供应链攻击事件),安全社区一直要求开发者在 YAML 文件里硬编码 40 位提交哈希。这种做法不仅让配置文件难以阅读、必须靠行尾注释记版本号,还留着明显的防御漏洞。Python 核心开发者 Hugo van Kemenade 在 2026 年 11 月 11 日分享的迁移实战展示了新方案的便利,但拆开这份格式版本为 v0.0.3 的锁文件就会发现,它比单纯搬移哈希值多干了两件大事。

补齐传递依赖与仓库劫持两大盲区

传统的内联 SHA 写法只能管住工作流顶层直接调用的 Action。一旦某个复合 Action(Composite Action)在内部嵌套调用了其他未固定哈希的第三方 Action,攻击者依然能顺着这条传递依赖链投毒。新的 actions.lock 会像前端的 package-lock.json 一样,把顶层依赖和传递依赖的精确提交哈希全部锁定在同一份文件里。

锁文件将顶层与嵌套的传递依赖全部锁定(剖面示意)
锁文件将顶层与嵌套的传递依赖全部锁定(剖面示意)

更关键的变化藏在锁文件新增的 owner_id 和 repo_id 两个纯数字字段里。在旧机制下,如果上游作者删除账号或重命名仓库,攻击者可以抢注同名账号与仓库,发动仓库劫持(Repo Jacking)。如今 GitHub 会在运行时核对锁文件里的数字身份 ID,哪怕路径名字一模一样,只要底层仓库 ID 对不上,流水线就会拒绝拉取代码。

GitHub Actions 两种依赖锁定机制安全边界对比 传统 YAML 内联 40 位 SHA • 可读性差,需手工维护版本尾注 • 仅锁定顶层直接调用的 Action • 漏放复合 Action 内部传递依赖 • 无法拦截同名仓库抢注劫持 • 支持锁定可复用工作流 新版版本标签 + actions.lock • YAML 恢复 vX.Y.Z 语义化标签 • 穿透锁定复合 Action 传递依赖 • 校验数字 owner_id 与 repo_id • 不支持锁定可复用工作流 • 未开强制策略时损坏文件静默放行

在周边工具链上,静态安全检查工具 zizmor 从 v1.32.0 版本开始原生识别锁文件,不再对已加锁的语义化标签报未固定哈希警告。自动更新工具也已跟进,但成熟度并不一致。Dependabot 可以顺畅更新现有锁文件,却不会替新增的工作流自动创建锁文件;而 Renovate 对 actions.lock 的支持在官方文档中目前仍处于实验性阶段。


静默放行漏洞与可复用工作流盲区

只生成锁文件并提交到仓库,并不等于给流水线装上了防盗门。为了兼容旧项目的渐进式迁移,GitHub 在底层设计上做了一个危险的妥协。

未开启后台强制策略时损坏的锁文件会静默放行(示意图)
未开启后台强制策略时损坏的锁文件会静默放行(示意图)
没有后台强制策略兜底的锁文件,只是一把挂在门把手上却没锁舌的君子锁。

根据社区公开反馈(Issue #125),如果团队没有在仓库或组织后台开启 Require lockfile 强制策略,一旦锁文件出现格式损坏(malformed),GitHub Actions 运行时不会报错阻断,而是触发静默放行(fail-open),直接退回无保护状态继续执行工作流。即便管理员在后台开启了强制拦截策略,目前未锁定的工作流在 Pull Request 检查中也只会卡在模糊的 Expected — Waiting 状态,缺乏明确的报错提示,容易拖慢日常排查效率。

  • 风险..github/workflows/actions.lock 目前不支持锁定通过 jobs.<job_id>.uses 调用的可复用工作流(Reusable Workflows),也不覆盖本地 ./... Action 和容器镜像摘要;企业在调用跨仓库可复用工作流时,仍必须在 YAML 中直接固定 40 位完整 SHA。

对于正在把 Pillow、CPython 等大型开源项目或企业内部仓库迁往新机制的工程团队来说,单靠本地跑一次 gh actions-lock 远远不够。要在生产环境真正堵住漏洞,团队必须把动作补全:

  1. 在组织或仓库后台开启 Require lockfile 强制策略堵死损坏文件静默放行的后门。
  2. 参照 Hugo van Kemenade 的做法在 CI 流水线中用轻量级 ubuntu-slim 运行器单独跑一个并行任务,固定安装 gh-actions-lock(如 v0.4.1)并执行 gh actions-lock --verify,把未同步或被篡改的锁文件直接拦截在合并前。
  3. 在 Dependabot 或 Renovate 中配置依赖冷却期(Cooldowns)避免上游刚发布带毒新版本就被自动化机器人秒级同步进锁文件。

接下来最值得盯紧的两个变量,一是 GitHub 何时修复 Issue #125 中损坏锁文件默认静默放行的机制缺陷,二是何时把可复用工作流纳入 actions.lock 的管辖范围。在这两块短板补齐之前,企业的 YAML 配置文件里注定还要留着一部分 40 位哈希值。