你的 CI/CD 流水线正在替攻击者打工——GitHub Actions 供应链安全完整复盘
你有没有想过:npm install 跑完的那一刻,你的 CI 流水线已经在替别人打工了。
2026 年上半年,GitHub 监测到针对开源供应链的攻击同比增长 340%,其中 CI/CD 环境是最常见的突破口。攻击者不再需要黑进你的服务器——他们只需要让你自己跑他们的代码。这就是 GitHub Actions 供应链攻击的逻辑。
攻击面一:Script Injection(脚本注入)
GitHub Actions 的 workflow 文件里充满了变量替换,这些 secrets 会直接进环境变量——但问题在于,某些”本不应该有 secrets” 的地方也在悄悄替换。
看一个典型场景。workflow 里有这样一行:
npm test — –grep “${{ github.event.head_commit.message }}”
这个 commit message 是谁写的?攻击者。只要有人提交一条特定构造的 commit 信息,CI 就会在测试命令里插入恶意命令。这不是假设,这是真实攻击手法,叫 script injection。
更隐蔽的版本是依赖混淆。攻击者把包名发布到 npm,版本号比你公司内部私有源里的更高。你的 CI 如果没有锁定私有源优先级,npm install 就会悄悄把攻击者的包拉进来。
Wiz 在 2026 年 Q2 的研究报告显示,他们扫描了 2000 个 GitHub Actions workflow,发现 67% 存在至少一种供应链暴露风险,其中 script injection 占 41%,依赖混淆占 28%。
真实案例:一家 SaaS 公司的完整沦陷路径
2026 年 4 月,一家中型 SaaS 公司发现生产数据库被清空。复盘发现攻击路径是这样的:
- 攻击者扫描 GitHub 找到了该公司的公开仓库
- workflow 文件里发现了一个写错的变量引用:secrets.PACAKGE_TOKEN(拼错了 PACKAGE)
- 这个拼写错误导致 GitHub Secret 根本没有注入,环境变量里留下的是空值
- npm install 命令用了这个空值,导致 npm 向上回退到公共 registry
- 攻击者在 npm 发布了一个同名的恶意包,版本号更高
- CI 跑完 npm install,恶意包被装进来
- postinstall 脚本拿到了 CI 环境的 npm token,进而拿到生产数据库凭证
整个过程没有”黑”任何系统——只是利用了 CI 配置里的一个拼写错误。
三步防住供应链攻击
第一步:锁定 registry 优先级
npm ci –prefer-offline
私有源一定要放在公共 registry 之前,而且 secrets 拼写要反复核对——GitHub 现在提供了 actions/checkout 的 token 传递安全建议。
第二步:用 OIDC 替代静态 secrets
传统的 secrets.GITHUB_TOKEN 是静态的,一旦泄露永远泄露。GitHub Actions 现在支持 OpenID Connect (OIDC),可以让每次 workflow 运行动态换取临时 token:
github-actions/configure-aws-credentials@v4 + role-to-assume + audience: https://github.com/${{ github.repository }}
这样云端的角色只需要 trust GitHub OIDC,不再需要存储任何长期 secrets。
第三步:workflow 内容审查
GitHub 提供了 CodeQL 和供应链安全功能,可以在 PR 层面检测 workflow 里的可疑模式:
- 未验证的 actions 引用(指向第三方仓库的 actions)
- 过度宽泛的 GITHUB_TOKEN 权限
- 外部网络调用(run 步骤里的 curl/wget)
开启 Dependency review action,每次 PR 都会对比依赖变化,发现新增的陌生包立即告警。
你的 CI/CD 环境比你想象的更脆弱
供应链攻击的本质不是”攻进”你的系统——是让你自己把门打开。GitHub Actions 的便利性恰好是它最大的风险:workflow 文件是代码,代码就应该被审查;依赖是攻击向量,向量就应该被锁定。
下一步:去你团队的 .github/workflows 目录,把 workflow 文件全扫一遍。拼写错误、registry 优先级、过度权限——这三个问题至少有一个会中枪。
评论区
登录后可评论。