你的公开仓库收到一个陌生人 PR,CI 跑起来的时候凭证可能已经不在你手里了
公共仓库收到一个陌生人的 PR,你点了合并。下一秒 CI 开始跑,但你不知道的是——攻击者已经在 workflow 文件里埋好了读取云凭证的步骤,等着凭证到手就悄悄把数据外传。
这件事从今天起被 GitHub 强制加了一个人工审批关卡。
攻击链是怎么成立的
GitHub 在 7 月 28 日宣布了一个新安全机制:公共仓库里被系统识别为可疑的工作流,现在会自动暂停,等待具有写权限的协作者在已认证的网页会话里批准后才会继续执行。
这个改动背后是真实攻击模式的驱动。近年三次高曝光的供应链攻击都用了同一套手法:
- s1ngularity 攻击:利用
pull_request_target触发器执行任意代码,污染了 Nx 等知名项目 - hackerbot-claw 活动:用 AI 驱动的自动化在超过一半的目标仓库里实现了远程代码执行
- TeamPCP:用被污染的 Trivy、KICS、LiteLLM 版本渗透 CI/CD 管道
Datadog 安全实验室的统计更让人不安:38% 的机构至少有一个 GitHub Actions 工作流存在脚本注入或危险触发器漏洞,而这个攻击链的成立条件出奇地低——攻击者只需要拿到一个 GitHub 账号,然后推送一个包含恶意步骤的 workflow 文件。
这个暂停机制是怎么工作的
新机制在 workflow 进入仓库和开始执行之间插入了一个人工审批节点:
- GitHub 的检测系统识别到某个 workflow 运行”行为异常”,触发暂停
- Workflow 不会立即执行,而是进入等待状态
- 具有仓库写权限的协作者收到通知
- 协作者必须通过已认证的 GitHub 网页会话(不是 API、不是 CLI)显式批准
- 批准后 workflow 按正常流程继续执行
关键细节:这个保护是 GitHub 自动开启的,仓库管理员不需要任何配置。它目前只适用于 github.com 上的公共仓库,GitHub Enterprise Server 不在范围内。
GitHub 没有披露具体的检测信号、阈值或误报率,所以这个机制的实际效果边界目前还不完全清晰。
对维护者的实际影响
如果你在维护一个活跃的公共开源项目,这项变更有几层含义:
直接改变的是响应方式。以前可疑的 workflow 进来直接跑,现在 CI 页面会多出一个”待审批”状态,要求你主动判断是否放行。这意味着维护者需要理解什么是正常的 workflow 行为——比如一个陌生人提交的 PR 触发了一个读取云凭证的 workflow,这显然是异常信号。
误报会带来额外负担。GitHub 没有公布检测机制细节,但从安全研究的角度,机器学习驱动的检测系统在初期往往有较高误报率。如果你经常收到”待审批”提示,需要在安全性和工作流效率之间找到平衡。
审批要求用网页会话完成,不能用 API 或 GitHub CLI。这意味着手机端无法处理这类审批,维护者需要确保自己在需要时能登录网页端处理。
这只是多层防御里的一层
这个暂停机制针对的是攻击链里的一个特定节点:恶意 workflow 文件已经进入仓库、但还没有实际执行的那一刻。但这不是银弹:
- 攻击者可能通过长期潜伏在贡献历史里,等待积累足够信任
- 如果维护者习惯了频繁点击批准,审批这个动作本身会流于形式
- GitHub Enterprise Server 用户目前没有这项保护
真正完整的防护仍然需要:最小权限原则(workflow 只申请必要的 token 范围)、OIDC 代替静态密钥、环境隔离(敏感 job 在独立 runner 上跑)、第三方 action 固定 SHA 而非版本标签。暂停机制是在这些基础之上再加一道人工关卡,而不是替代它们。
三步下一步
现在就能做的一件事:打开你公共仓库的 Actions 页面,看看是否有关于”held for approval”的说明文档,把这个流程写进项目的安全响应文档里,让所有维护者知道遇到这种情况应该怎么判断。
本周能做的事:检查你仓库里 workflow 文件的触发器和权限声明,删除不必要的 write 权限和 pull_request_target 触发器,这是目前被利用最多的两个攻击向量。
长期要做的事:把 workflow 安全的审计纳入常规安全检查,用 Datadog、Semgrep 或 GitHub 自带的安全功能定期扫描 workflow 配置里的危险模式。
这个暂停机制的出现,本质上是把”credential compromise 导致 workflow 被劫持”这件事从”静默发生”变成了”必须人工确认”。这是对的——但最终安全靠的仍然是每个维护者知道自己在批什么。
评论区
登录后可评论。