大家好,我是蓝戒。本篇我们来聊聊:“wfx供应链大劫持”。
如果你的团队平时使用 GitHub Actions 做自动化构建发布,或者在仓库里配置了直连 AWS、Azure、GCP 云平台的部署权限,请务必放下手头的工作,花十分钟把这篇文章里的自查清单跑一遍。
就在 11 月 11 日至 12 日,国际安全机构 Aikido Security、SafeDep 与 Phoenix Security 联合拉响了最高级别的软件供应链警报:从北京时间 11 月 10 日晚间开始,一场代号为 wfx(又称 wfx-loot) 的大规模自动化凭据劫持风暴正在席卷 GitHub。
截至目前,攻击者已经利用手里掌握的 4,837 个被盗 GitHub 开发者与机器人账号凭据,向多达 61,764 个代码仓库发起了写权限试探,并在确认有权限的 8,093 个公开仓库中成功植入了长达 1,500 行的恶意窃密脚本(其中已确认至少有 1,806 至 1,835 个仓库的 CI 流水线被实际触发执行,连知名测试框架 WebdriverIO 旗下的 28 个仓库都因机器人账号 wdio-bot 令牌泄露而中招)。
比感染规模更让人后背发凉的,是这次攻击者的两条毒辣手段:
- 第一是“投完毒 4 分钟内自己擦干净痕迹”:恶意代码在流水线里跑完、偷光密钥后,会在短短几分钟内自动提交一次还原操作(Revert),并顺手把刚刚运行过的 GitHub Actions 构建记录和日志删得干干净净。你打开仓库主分支看一眼,代码清清爽爽,完全看不出半点异常。
- 第二是“就算你把 GitHub 里的密钥全换一遍也没用”:脚本在偷走密钥的同时,会直接利用 GitHub 的免密身份令牌(OIDC)登录进你的 AWS 和 Azure 云账号,反手修改云端的角色信任策略并塞入后门身份。即便你在 GitHub 后台重置了所有密码,黑客依然能大摇大摆地直连你的生产云环境!
今天咱们就剥开这起史上罕见的 CI 供应链连环劫持案,把它的四步作案手法、中毒特征(IoC)以及从 GitHub 到云端后门的六步彻底拔除实操一次性讲透。
一、还原作案全流程:黑客是怎么在 4 分钟内“偷光家底又毁尸灭迹”的?
很多开发者看到新闻的第一反应是:GitHub 是不是出了什么底层代码漏洞?
安全机构在复盘后给出了明确结论:没有任何平台漏洞,黑客用的是货真价实的合法开发者令牌(Token)。而且数据比对发现,这次沦陷的 4,837 个账号,与今年 10 月份那波 GhostAction 攻击的受害者高度重合(中招概率是普通账号的 1,000 倍)——说明黑客手里攥着一批此前通过木马、恶意插件或泄露的 gh 命令行配置搜集来的长效令牌,正在进行工业化、全自动的“二次收割”。
整个自动化攻击流水线分为环环相扣的四个阶段:
1. 第一阶段:发一个看似无害的文档 PR“投石问路”
黑客拿到一批被盗 Token 后,并不知道哪些 Token 还有写权限、能写哪些仓库(包括该开发者作为外部协作者或组织成员有权限修改的公司仓库)。
于是,自动化脚本会先在所有能碰到的仓库里建一个名为 wfx-docs 的分支,并提交一个标题极其正常、极具迷惑性的合并请求(Pull Request):docs: dependency audit notes(正文写着 Routine dependency audit notes.)。
在这个阶段,攻击者在 61,764 个仓库(其中包含 10,431 个跨组织协作仓库)里刷出了超过 6.3 万个试探性 PR,且目前 91% 以上还挂在那里没关。请注意:哪怕你的仓库只收到了这个 wfx-docs 的试探 PR、后续没有恶意提交,也已经 100% 证明发起该 PR 的开发者账号令牌已经落在黑客手里了!
2. 第二阶段:三种姿势植入 1,500 行窃密代码(连本地 npm install 都抓)
一旦确认某个账号对仓库拥有直接推送(Push)权限,黑客脚本会立刻从以下三种方式中挑一种植入名为 wfx 的恶意载荷:
| 植入方式 | 伪装的 Git 提交信息(Commit Message) | 已确认中招仓库数 | 危险范围与触发条件 |
| 1. 篡改现有工作流文件 | ci: refresh build cache | 7,309 个仓库 | 向现有的 .github/workflows/*.yml 追加约 1,500 行代码,一推代码即在云端 CI 触发 |
| 2. 植入 npm 安装钩子 | chore: add ci helper | 771 个仓库 | 在根目录塞入隐藏脚本 .ci-xxxxxx.sh 并写入 package.json 的 postinstall,开发者本地敲 npm install 也会当场中招! |
| 3. 空仓库新建工作流 | chore: add dependency audit workflow | 16 个仓库 | 先推一个 chore: initial commit,再塞入 .github/workflows/build-audit-xxxxxx.yml |
在被篡改的 GitHub Actions 工作流里,恶意代码会专门申请 id-token: write(允许签发云端 OIDC 身份令牌)和 statuses: write 权限,随后执行一段只有短短几行却极其致命的环境变量导出脚本,将运行时底层的 ACTIONS_RUNTIME_TOKEN 以及仓库里配置的所有机密变量 ${{ toJSON(secrets) }} 和 ${{ toJSON(vars) }} 全部打包喂给恶意脚本。
3. 第三阶段:抽干内存与文件(连你的 OpenAI 和 Claude Key 都不放过)
一旦脚本在 GitHub Actions 运行器(或者开发者的本地电脑)上跑起来,它会开启 WF_MEMSCAN='1'(内存扫描模式),像吸尘器一样把能摸到的所有敏感资产洗劫一空:
- CI 机密与运行内存:不仅拿走 GitHub Actions 里的所有 Secrets,还会直接扫描运行器进程的物理内存(Process Memory),把内存里明文闪过的 OpenAI、Anthropic(Claude)、Cursor、Copilot 等大模型 API 密钥以及 AWS、GitHub 临时令牌全部抠出来;
- 本地与构建机敏感文件:自动打包读取
.env、Terraform 状态文件(*.tfvars、*.tfstate)、~/.ssh私钥、~/.gnupg、Kubernetes 配置文件kubeconfig、终端历史命令记录(Shell History)乃至本地加密钱包文件; - 多通道外发赃物:把打包好的机密通过 HTTP POST 直接发往黑客控制的服务器(如
194.150.166[.]244:8080/exfil等),或者通过 5 个内置的 Telegram 机器人直接发进黑客的电报群(群 ID 为-1004340163187)。
紧接着,在SafeDep追踪的真实案例中(例如下午 14:01 植入),黑客在 14:05(仅隔 4 分钟) 就会自动推送名为 ci: restore 和 ci: cleanup 的提交把恶意代码撤回,并调用接口把刚刚那次 GitHub Actions 的运行记录和日志彻底删除!
二、最致命的杀招:为什么重置了 GitHub 密钥,黑客依然能进你的云内网?
如果这只是一次普通的“偷完钥匙就跑”的攻击,那安全团队只需要去后台把泄露的 API Key 删掉重发一把就完事了。
但 wfx 最阴险的地方在于第四阶段——利用 OIDC 令牌在你的云账号里打下“永久暗桩”。
现在很多现代研发团队为了安全,不在 GitHub 里存死密码,而是用 GitHub Actions 的 OIDC(开放身份认证)直接免密换取 AWS、Azure、GCP、HashiCorp Vault 或 Kubernetes 的临时会话。结果 wfx 脚本趁着自己在 CI 里合法运行的那几十秒,直接拿这枚 OIDC 令牌登进了你的云平台,并干了两件绝户事:
- 在 AWS 上的“开门揖盗”后门:脚本以名为
wfx-<进程号>的会话身份进入你的 AWS 账号后,一方面调用CreateAccessKey给 IAM 用户新建一把长期有效的访问密钥;另一方面直接调用UpdateAssumeRolePolicy修改你原有 IAM 角色的信任策略(Trust Policy)——把原本“只允许你自己的代码仓库扮演该角色”,改成了“允许任意外部 AWS 账号扮演该角色”!这意味着什么?意味着就算你把 GitHub 仓库删了、把所有静态密码全换了,黑客坐在自己的电脑前,用他自己的 AWS 账号随时都能一行命令切进你的生产环境! - 在微软 Azure 上的“幽灵联邦凭证”后门:如果检测到你有 Azure 权限,脚本会在你的 Entra ID(原 Azure AD)应用注册里,悄悄新增一条名为
wfx-ci-<数字>的联合身份凭证(Federated Identity Credential)。只要这条记录没删,任何满足其预设条件的外部工作流无需任何密码就能直接登录你的 Azure 云服务。
此外,由于部分受害仓库配置了“只要有代码提交就自动打包发版”的流水线,wfx 恶意脚本还顺着自动发版流混进了 3 个公开软件包里:包括 PHP Packagist 上的 AI 开发包 digitalelvis/neuronai-studio(v3.14.3 版本,注意:执行 composer install 不会触发,但进入该目录执行 npm install 会当场触发),以及两个 Go 语言模块 [github.com/vkuznet/gocurl](https://github.com/vkuznet/gocurl) 与 [github.com/onuragtas/redock](https://github.com/onuragtas/redock)(含 docker-env 的 v1.0.278、v1.0.280、v1.0.282 版本)。
三、十分钟极速排雷实操:从 Git 历史到云端后门的六步自救指南
面对这种会自动删日志、自动撤回代码的“无痕攻击”,只看代码仓库的当前文件是绝对查不出来的。请所有研发和运维团队立刻按以下六步执行排查与清理:
第一步:用命令行搜出被撤回的“幽灵提交”与试探分支
打开你的终端,在团队所有仓库(记得加 --all 扫描所有分支)中运行以下 Git 历史排查命令,看看从 11 月 10 日以来有没有出现过特征提交:
Bash
# 1. 检查是否存在 wfx-docs 或 ci-check-* 恶意试探分支
git branch -a | grep -E "wfx-docs|ci-check-"
# 2. 在全部分支历史中搜索 wfx 的五大特征提交信息(即使已被 revert 也会留在历史中)
git log --all --since="2026-11-09" --grep="docs: dependency audit notes\|ci: refresh build cache\|chore: add ci helper\|chore: add dependency audit workflow\|ci: restore\|ci: cleanup" --oneline
# 3. 检查是否存在残留的隐藏脚本或异常 workflow 文件
find . -maxdepth 3 -name ".ci-*.sh" -o -name "build-audit-*.yml"
此外,如果你是 GitHub 组织管理员,请立刻去组织的 Audit Log(审计日志) 中搜索被删除的 Actions 运行记录(因为黑客删得掉构建面板,但删不掉组织级的底层审计日志),重点关注提交记录序号出现断层(Missing run number)的异常提交。
第二步:揪出“内鬼账号”,彻底作废其全部个人令牌
一旦在某个仓库里发现了 wfx-docs 分支或上述恶意提交,千万别只关掉 PR 就不管了!请立刻查看那条恶意提交的作者(Commit Author)是谁——那个人的 GitHub 账号就是整起入侵的突破口:
- 立即前往该账号的 GitHub 设置页面,吊销其名下所有的 Personal Access Tokens(PAT)、OAuth App 授权(重点检查泄露重灾区
ghCLI 令牌)、SSH 密钥并强制登出所有活跃网页会话; - 强制开启硬件级或验证器双因素认证(2FA);
- 如果有开发人员在 11 月 10 日后拉取过含
chore: add ci helper提交的代码并运行了npm install,请将该程序员的笔记本电脑视为已沦陷主机,立即重装或全面轮换其电脑上存过的所有 SSH 私钥、云命令行凭证与大模型 API Key!
第三步:去 AWS、Azure 和 GCP 后台拔掉“持久化暗桩”(最关键!)
如果恶意脚本已经在你的仓库里跑过,在更换密码前,必须先把云端的后门拆掉:
Bash
# 【AWS 排查】在 CloudTrail 日志中检索会话名以 wfx- 开头的越权操作,并核查所有角色的信任策略:
aws cloudtrail lookup-events --lookup-attributes AttributeKey=Username,AttributeValue=wfx-
# 重点检查是否有异常的 CreateAccessKey(新建长效密钥)和 UpdateAssumeRolePolicy(篡改角色信任策略),将信任策略改回严格限制具体仓库与分支!
# 【Azure 排查】在 Entra ID 应用注册中查找并删除所有以 wfx-ci- 开头的异常联合身份凭证:
az ad app federated-credential list --id <你的应用Object-ID> --query "[?starts_with(name, 'wfx-ci-')]"
同时,使用 GCP 的团队请检查 Workload Identity Pool 中是否有异常的 GenerateAccessToken 与 SignJwt 调用;使用 HashiCorp Vault 的团队请审计来自 GitHub OIDC 签发者的异常 JWT 登录记录。
第四步:全量轮换 CI 密钥与大模型 API Key
在拔掉云端后门、封堵被盗账号之后,再将该仓库及所属组织(Organization)在 GitHub Actions 中能访问到的所有 Secrets、环境变量、发包令牌(npm、PyPI、Packagist、Go、crates.io)以及运行器内存里可能接触到的 OpenAI / Claude 等第三方密钥全部作废重发。
第五步:拦截三个已被污染的下游开源包版本
检查你们项目的依赖锁文件(composer.lock、go.sum、package-lock.json),如果用到了以下三个包,请立即锁定回安全版本:
- Packagist 包
digitalelvis/neuronai-studio:严禁使用v3.14.3(目前官方源仍将其标为最新版),请强制降级锁定至v3.14.2或更早版本; - Go 模块
[github.com/vkuznet/gocurl](https://github.com/vkuznet/gocurl):封禁伪版本v0.0.0-20261111095532-8d5aad0cb0da; - Go 模块
[github.com/onuragtas/redock](https://github.com/onuragtas/redock)(及docker-env):封禁中毒的v1.0.278、v1.0.280、v1.0.282版本,锁定至干净的v1.0.277。
第六步:给仓库加上两把“长效防盗锁”
为了防止未来团队里再有人不慎泄露 Token 导致全盘皆输,建议今天就在仓库设置里落实两条硬规矩:
- 开启默认分支保护并强制要求“签名提交(Require signed commits)”:这是这次
wfx攻击能一路绿灯的最大软肋——黑客拿着偷来的 Token 伪造提交时,是没有开发者本地 GPG/SSH 私钥来做数字签名的。只要你在主分支开启强制签名校验,黑客就算偷走了 Token 也休想往主分支里塞进一行代码! - 收紧
id-token: write与云端 OIDC 信任范围:不需要连云平台的工作流一律拿掉id-token: write权限;在 AWS 和 Azure 配置 OIDC 信任条件时,千万不要图省事写宽泛的repo:组织名/*,必须精确锁死到具体的仓库名、具体的生产分支(ref:refs/heads/main)和具体的工作流文件。
在 AI 与自动化工具满天飞的今天,黑客早就不再靠手工一个个敲命令找漏洞了——4,837 个被盗账号在几小时内就能把 6 万多个仓库犁一遍。赶紧把上面的三行 Git 自查命令发到你们的研发群里跑一下,确认平安无事才是最踏实的!
相关参考与排查资源
- SafeDep 官方 8,093 个受影响公开仓库完整核查清单与 IoC 汇总:
[https://safedep.io/blog/github-actions-wfx-credential-stealer](https://safedep.io/blog/github-actions-wfx-credential-stealer) - SafeDep 开源恶意包实时拦截工具 PMG(Package Manager Guard)仓库:
[https://github.com/safedep/pmg](https://github.com/safedep/pmg) - Phoenix Security 关于 wfx 攻击流、AWS/Azure 云端后门与修复手册:
[https://phoenix.security/wfx-github-actions-credential-stealer-ci-secret-theft/](https://phoenix.security/wfx-github-actions-credential-stealer-ci-secret-theft/) - The Hacker News 深度追踪报道:
[https://thehackernews.com/2026/11/4837-hijacked-github-accounts-ran-ci.html](https://thehackernews.com/2026/11/4837-hijacked-github-accounts-ran-ci.html) - Chainguard 关于 wfx-loot 供应链影响范围通报:
[https://www.chainguard.dev/unchained/wfx-loot-stolen-github-tokens-pushed-a-ci-secret-stealer-into-60-000-repositories-november-2026](https://www.chainguard.dev/unchained/wfx-loot-stolen-github-tokens-pushed-a-ci-secret-stealer-into-60-000-repositories-november-2026)
文章评论