上一秒还在想「谁没事盯我仓库」,下一秒 git ls-remote 一拉,多出来一个 ci-sync-a3f9k2 分支。它不是谁在改代码,是有人拿了一个偷来的 GitHub token,在你仓库里做了一件平台本来就允许的事——把 secret 打印到日志里。

先把话说前头:这不是哪个软件出了漏洞。攻击者用的是偷来的 token,所以他能进哪些仓库、能干多少事,全看那个 token 当初被授了多大权限。

动作很固定,就三步:

  1. 用 token 在每个有权限的仓库建一个分支,名字是 ci-sync- 加 6 位随机字符;
  2. 提交一个 .github/workflows/sync-check.yml,commit message 固定写 ci: sync config,没签名,作者显示成 token 的主人;
  3. 这个 workflow 只干一件事——把 toJSON(secrets) 打出来。

关键就在第 3 步。GitHub 给日志打码,只对原样出现的 secret 生效。工具把 secret 先做一次 base32 编码再打印,编码后的串跟原值对不上,打码逻辑就绕过去了,明文落进日志。

紧接着,工具通过 GitHub 自己的 API 把这次 run 的日志拉走,几秒内把 run 删掉。等你再打开 Actions 页面,什么痕迹都没有。

这也是它躲得出网告警的原因:整条外泄走的是 GitHub 自己的 API,没有攻击者域名、没有异常外连,在监控眼里就是「你们家 CI 在拉自己的日志」。

哪些仓库挡得住、哪些挡不住,这点值得记一下:公开仓库有 7/28 上线的「可疑 workflow 需人工批准」盯着,会拦;私有仓库和 GitHub Enterprise Server 不适用这条——已经观察到私有仓库里的 run 正常跑完、然后被删。有 environment 的仓库还要更糟一层:攻击者用 job matrix 把 environment 级的 secret 也打出来,而 environment 里放的通常就是生产凭证。

顺带一句,像 permissions: {} 这种收紧,限制的是 GITHUB_TOKEN,管不到 secrets 这个上下文,别指望它兜底。

企业环境里的后续通常是:几分钟内轮换多个用户和自动化账号的 token,先把私有仓库 clone 走;几个小时后,同一个组织在云上的凭证开始被拿去枚举 AWS Secrets Manager。

影响面:850+ 个账号、13,500+ 个植入分支,从个人项目到企业私有仓库。凭证来源是 infostealer 日志,以及此前供应链事件(比如 3 月 Trivy)里漏出去的 token。

修复版本:不适用,它不是软件漏洞。要做的处置是:轮换该仓库能见到的全部 secret、revoke 掉 token。如果有 self-hosted runner 跑过这个 workflow,那台机器直接当失陷处理。

一条自查:git ls-remote --heads origin 'refs/heads/ci-sync-*',有输出就是被种过。

这跟之前那次 GitLab 自己的 CI 洞 是一个道理:大家平时防的是出网、防的是恶意依赖,很少有人防「平台自带的功能被拿来当外泄通道」。也像更早 堡垒机那次——不是洞有多高明,是拿到的凭证能用多久、能走多远,没人算过账。

原始来源:Wiz Research《Gheist: attempted scaled abuse of stolen GitHub tokens stumbles》:https://www.wiz.io/blog/gheist-attempted-scaled-abuse-of-stolen-github-tokens-stumbles