攻击原理:借你的令牌,用你的仓库

Wiz Research 自 9 月 15 日起追踪这起命名为 Gheist 的自动化活动。攻击者的入口是被窃的 GitHub 令牌:拿到令牌后,工具枚举该令牌能触及的每一个仓库,为每个仓库新建名为 ci-sync- 加六位随机字符的分支,提交一份 .github/workflows/sync-check.yml,提交信息写成「ci: sync config」。推送触发工作流,工作流把仓库密钥乃至环境密钥打印进运行日志;攻击者再通过 GitHub API 下载日志,并在数秒后删除这次运行,证据随之一并消失。整条链不依赖任何外部命令与控制服务器。

规模:850+ 账号、1.3 万条分支

Wiz 截至 10 月 24 日已从 850 多个被攻陷账号中恢复超过 13,500 条被植入的分支,范围从个人项目一路延伸到企业组织的私有仓库。攻击仍在演进:约三分之二的涉事账号已不再可用,说明响应正在进行,但私有仓库与 GitHub Enterprise Server 环境中仍观察到成功利用与后续活动。The Hacker News 于 10 月 26 日报道了这份研究。

从被盗令牌到密钥外泄的五步窃令牌→植分支→跑工作流→取日志→删运行规模:850+ 账号 · 13,500+ 恶意分支 · 私有仓库与 GHE 已得手密钥经 base32 编码绕过日志掩码,从 GitHub API 离场,无外部 C2公开仓库已被审批闸门拦下;私有仓库与 GHE 仍是盲区防护:搜 ci-sync- 分支、轮换密钥、短时效令牌、自托管运行器视为已陷
Gheist 窃密链:借合法令牌,走 GitHub 自己的通道

为什么难防:没有 C2,全是 GitHub 自己的通道

这起攻击最棘手的地方在于「无外联」。窃取的密钥从 GitHub 自身的 API 离开,防御者没有可供拦截的出站连接,信号只能散落在 GitHub 与云的审计日志里。更隐蔽的是日志遮蔽被绕过:GitHub 只在密钥原样出现时做掩码,而攻击者先把密钥做 base32 编码再打印,掩码机制认不出,明文就此暴露。设置 permissions 为空只限制工作流自身的令牌,拦不住 secrets 上下文——这是很多团队会忽略的盲区。

从仓库密钥到云基础设施

风险不止于源码。Wiz 观察到,在企业组织里,工具会在数分钟内轮换多名用户与自动化账号的令牌,先克隆私有仓库,数小时后又用同一组织的云凭据枚举 AWS Secrets Manager。后续变体还新增了面向自托管运行器的 sync-host 作业,借 Docker 套接字挂载宿主机根文件系统,搜索 31 种令牌格式、进程环境、Kubernetes 服务账号令牌等。换句话说,一枚被窃的 GitHub 令牌,可能成为通向云上生产凭证的跳板。

防护:审批闸门只覆盖了一半

好消息是 GitHub 自 7 月 28 日起要求协作者手动审批被标记为可疑的工作流运行,Wiz 确认这道闸拦下了每一次针对公开仓库的 Gheist 尝试。坏消息是:该审批要求不覆盖私有仓库与 GitHub Enterprise Server,而那里正是 Gheist 得手的地方。应对建议很明确:在审计日志里搜索 ci-sync- 命名分支并审查相关 OIDC 角色假设;任何被波及仓库可触达的密钥一律视为已泄露并轮换;用 GitHub Apps 或短时效令牌替换长期个人访问令牌;执行过 ci-sync 工作流的自托管运行器应视为已被攻陷的机器,而非简单清理后复用。

冷静看:已披露,仍在演进

需要厘清边界:这不是 GitHub 平台的代码漏洞,而是对合法开发者凭据的滥用,根子在更早的凭据泄露与供应链失陷。Wiz 已向 GitHub 报告,公开仓库一侧已被有效阻断,但私有与 GHE 环境仍是现实盲区。对依赖 GitHub Actions 与云集成的团队,这起事件把一条旧常识重新摆上台面:长寿命令牌就是暴露面,最小权限与短时效不是可选项,而是 CI/CD 与云凭证隔离的底线。