跳到正文
>_ITDITDWeb 安全平台

安全事故与漏洞

Codecov 篡改事件(2021)——CI 中『被信任的工具』被劫持导致机密信息外泄的原因与防御

2021 年,开发工具 Codecov 的「Bash Uploader」(在 CI 中以 curl|bash 方式执行的脚本)在上游被篡改,长达约两个月,使用该工具的企业的 CI 环境中的机密信息(API 密钥、令牌、认证信息)被发送到外部。最终发现它的,是某一家公司的校验和比对。HashiCorp、Twilio 等还发生了二次受害。本文把供应链攻击的连锁拆解为一张防御地图,仅凭公开记录的事实,讲解让你的 CI 不再重蹈覆辙的具体做法(取得物的完整性校验、CI 机密的最小权限、轮换、egress 监控)。

发布于 2026-06-07 更新于 2026-06-07 3 分钟阅读

我们以 「在你的环境中如何防御」 的视角来解读真实发生过的公开事故,而不是把新闻重播一遍。本文是 基于公开记录(官方事后分析、CISA、安全企业的分析)的讲解。出处在文末注明。

约两个月
未被察觉的时间
〜29,000
可能受影响的客户数
SHA 比对
唯一的检测手段
二次受害
HashiCorp/Twilio 等
事故摘要 / CASE FILE
对象
Codecov(代码覆盖率测量工具)及其使用企业的 CI
公布
2021 年 4 月 15 日(篡改始于 1 月 31 日/发觉于 4 月 1 日)
手法分类
供应链攻击(对被信任的分发物进行上游篡改)+窃取 CI 机密信息
影响规模
Codecov 的大量客户(最多约 29,000)。HashiCorp、Twilio、Rapid7 等发生二次受害
根本原因
CI 未校验取得物就执行 + 分发源密钥管理不当 + CI 机密过度暴露
核心对策
取得物的完整性校验、CI 机密的最小权限、轮换、egress 监控

发生了什么(通俗版)

很多开发团队会在测试自动执行环境(CI)里,用 curl … | bash 这样的方式把外部工具取下来直接执行。Codecov 的 Bash Uploader 就是这样一个脚本。

攻击者利用 Codecov 一侧分发机制的缺陷,改写了被分发的脚本本体,让它在 CI 中执行时,把该环境里的环境变量(机密信息)发送到外部的服务器。从使用方看来,不过是像往常一样调用了被信任的工具而已。由于自己的代码一行都没变,几乎找不到察觉异常的线索。

约两个月后,某家使用企业把脚本的 校验和(SHA256)与官方的值进行了比对,发现了不一致,到这里篡改才终于暴露。可能外泄的信息里包含云的密钥、部署密钥、API 密钥、令牌等,并由此连锁引发了 对 HashiCorp、Twilio 等其他公司的二次受害

正因为『自己的代码毫发无损』才可怕

供应链攻击瞄准的不是你写的代码,而是你信任并引入之物。所以无论是代码审查还是日志都很难察觉。「信任=没有校验」正是漏洞所在。

连锁同时也是『一张防御地图』

重要的是,这是一条 四跳 的连锁,而每一跳都有可以阻断的地方。请不要把它读作攻击步骤,而要读作在哪里可以斩断

① 用 curl | bash 执行被信任的工具(未校验内容)

⊘ 阻断点:固定取得物+校验和验证 / vendoring

② 该分发物在『上游』被替换

自己的代码毫发无损,所以无从察觉。

⊘ 阻断点:与已知良好的哈希比对、使用固定版本

③ CI 内的环境变量(机密、密钥、令牌)被发送到外部

⊘ 阻断点:把 CI 机密收紧到最小权限、按步骤限定(不要把全部 env 都传过去)

④ 用偷来的密钥向生产环境、其他服务波及二次受害

⊘ 阻断点:密钥的定期轮换+egress(外向通信)监控

每一段都『能够被阻止』。校验所信任之物、收紧机密、轮换、盯住出口,层层叠加。

已公布的时间线

  1. 2021-01-31

    Bash Uploader 的篡改开始(此后断断续续)。
  2. 2021-03〜

    使用企业的 CI 中的机密信息持续被发送到外部(无人察觉)。
  3. 2021-04-01

    某客户发现校验和不一致并上报。
  4. 2021-04-15

    Codecov 正式公布。建议使用企业全面更换机密。
  5. 2021-04〜

    HashiCorp、Twilio、Rapid7 等的二次受害陆续查明。Codecov 后来废弃了 Bash Uploader。

根本原因并非『某一个失误』

如果以「都怪 Codecov」收场,就会重演。在使用方这一侧,也存在层层防线的崩塌

崩塌的配置(事故时)

  • CI 未校验取得物就执行(把 curl | bash 全凭信任)
  • CI 机密过度暴露(所有步骤都能看到全部环境变量)
  • 机密的轮换很少(被偷的密钥长期有效)
  • 不监控 CI 的外向通信

守住的配置(防止重演)

  • 取得物采用固定版本+校验和验证,或自行引入(vendoring)
  • CI 机密以最小权限、只在必要的步骤传递
  • 机密定期轮换(即便泄露也让寿命很短)
  • 监控 CI 的 egress,检测向陌生目的地的发送

『信任』要与校验成套

供应链攻击瞄准依赖库、CI 工具、构建镜像等「信任并引入之物」XZ Utils 事件也是同一种结构。把信任最小化,并对引入之物的完整性进行机械化校验,才是正解。

在你的环境中如何防止重演

下面是无论规模大小都有效、按优先级排序的对策。把「CI 究竟信任并执行了什么」盘点一次,就会变成自己的事。

1

校验取得物的完整性(不要把 curl|bash 全凭信任)

若要在 CI 中引入外部脚本或二进制,请把固定版本(版本/提交固定)+校验和(SHA256)比对作为必须项。可能的话就引入到自己的仓库(vendoring)。这次的检测,靠的也正是这种比对。

2

把 CI 的机密最小权限化、按作用域限定

不要把全部环境变量传给所有步骤。只把需要的机密传给需要的作业、步骤。使用短命令牌(OIDC 等),减少长期密钥的常驻。

3

定期轮换机密

即便被偷,寿命短则受害有限。把定期轮换做成机制,一旦有供应链事件被报道就立即轮换

4

监控 CI 的外向通信(egress)

让 CI 向陌生目的地的发送能够被检测到。即便在入口处没能完全挡住,也要留下一层能在外泄环节察觉的防线。

本站的立场:最小化信任,并加以校验

本站自身也是以用机器校验依赖与构建引入物为前提来设计的。Codecov 事件与 XZ Utils 揭示的是同一件事——「在信任」很容易变成「没在校验」,而那里正是供应链攻击的入口。减少信任、对引入之物的完整性进行机械化确认,这是对当事方、对公开事故都共通的结论。

出处(公开记录)

本文的事实基于以下公开信息。不涉及攻击的复现步骤与篡改代码,只聚焦于防御的教训

  • Codecov 官方「Post-Mortem / Root Cause Analysis (April 2021)」— about.codecov.io
  • Codecov 官方「Bash Uploader Security Update」— about.codecov.io
  • CISA「Codecov Releases New Detections for Supply Chain Compromise」(2021) — cisa.gov
  • Rapid7「Analysis of the Codecov Supply Chain Compromise」(2021) — rapid7.com

接下来阅读

FAQ

QCodecov 事件的根本原因是什么?
A

并不是自己代码的 bug,而是『在 CI 中信任并执行的外部工具(Codecov 的 Bash Uploader),在分发源(上游)被篡改了』。CI 只是用 curl 把那个脚本取下来、未校验内容就直接执行,于是被篡改的版本照常运行,CI 内的环境变量(机密信息)被发送到了外部。

Q为什么约两个月都没能察觉?
A

因为被篡改的是『别家的工具』,自己的仓库和代码毫发无损。日志里也不会出现显眼的异常。最终能够发现,是因为某家使用方把脚本的校验和(SHA256)与官方值进行了比对,找出了不一致。

Q小规模开发也有关系吗?
A

有。用 `curl … | bash` 把工具引入 CI 的做法在个人开发中也很常见,那里一旦被劫持,CI 的机密就会被一举抽走。本文的对策(取得物的固定+校验和验证、CI 机密的最小权限、定期轮换)无论规模大小都有效。