How 23,000 Repos Got Their Secrets Stolen Through Their Own CI/CD Pipeline
How 23,000 Repos Got Their Secrets Stolen Through Their Own CI/CD Pipeline
23,000 个代码仓库是如何通过自身的 CI/CD 流水线泄露密钥的
Been thinking about writing this one for a while. Supply chain attacks against CI/CD pipelines have been picking up pace over the past two years and the March 2025 tj-actions incident was the one that finally made me sit down and document everything properly. This is how I think about hardening GitHub Actions pipelines and what I actually do in practice. Original is on my blog but happy to have the conversation here too.
我考虑写这篇文章已经有一段时间了。过去两年里,针对 CI/CD 流水线的供应链攻击日益频繁,而 2025 年 3 月发生的 tj-actions 事件最终促使我坐下来,将这一切完整地记录下来。以下是我对加固 GitHub Actions 流水线的思考,以及我在实践中的具体做法。原文发布在我的博客上,但也很高兴能在这里与大家交流。
On a regular Tuesday morning, your engineering team pushes code, the pipeline runs like it always does, and somewhere in those automated logs, your AWS access keys, your GitHub tokens, your RSA private keys, are being quietly printed out and collected by someone you have never met. You are not notified. No alarm goes off. GitHub does not send an email. Your pipeline shows green. That is not a hypothetical. That is exactly what happened to over 23,000 teams in March 2025.
在一个普通的周二早晨,你的工程团队推送了代码,流水线像往常一样运行。在那些自动生成的日志中,你的 AWS 访问密钥、GitHub 令牌、RSA 私钥正被悄悄打印出来,并被一个你从未谋面的人收集。你没有收到通知,没有警报响起,GitHub 也没有发送邮件,你的流水线显示一切正常。这并非假设,而是 2025 年 3 月发生在超过 23,000 个团队身上的真实事件。
I have spent years working at the intersection of software engineering and security, where pipelines were moving over a billion dollars in monetary transactions, and more recently building Nexloy, a self-hosted deployment platform where I had to make every security decision from scratch. What I am about to share is the pattern I have watched attackers exploit again and again, the mistakes I have seen brilliant teams make, and the seven specific things that actually work when you need to lock down a GitHub Actions pipeline. By the end of this article you will understand exactly how these attacks happen, why your pipeline is more exposed than you probably think, and what you can do about it today. Some of these changes take five minutes. Some take an afternoon. All of them matter. Stay with me.
我多年来一直从事软件工程与安全交叉领域的工作,曾负责处理涉及超过十亿美元交易的流水线;最近我正在构建 Nexloy,这是一个自托管的部署平台,我必须从零开始做出每一个安全决策。接下来我要分享的是我反复观察到的攻击者利用的模式,我见过优秀团队所犯的错误,以及当你需要锁定 GitHub Actions 流水线时真正有效的七个具体措施。读完本文,你将确切了解这些攻击是如何发生的,为什么你的流水线比你想象的更脆弱,以及你今天可以采取什么行动。其中一些改动只需五分钟,有些则需要一个下午,但它们都很重要。请继续阅读。
The Attack That Woke the Industry Up
唤醒行业的攻击事件
In March 2025, engineering teams at over 23,000 companies opened their workflow logs and found something horrifying. Their most sensitive credentials were sitting there, printed in plain text, for anyone with access to those logs to read. We are talking about AWS (Amazon Web Services) access keys, GitHub PATs (Personal Access Tokens, which are like passwords that give programmatic access to your codebase), RSA private keys (cryptographic keys used to prove identity and encrypt data), and npm tokens (credentials for publishing software packages).
2025 年 3 月,超过 23,000 家公司的工程团队打开他们的工作流日志时,发现了令人恐惧的一幕:他们最敏感的凭据以明文形式打印在日志中,任何有权访问这些日志的人都能读取。这些凭据包括 AWS 访问密钥、GitHub PAT(个人访问令牌,类似于授予代码库程序化访问权限的密码)、RSA 私钥(用于证明身份和加密数据的加密密钥)以及 npm 令牌(用于发布软件包的凭据)。
The cause was not a sophisticated zero-day exploit. It was not a nation-state attacker breaching GitHub’s own servers. It was something almost embarrassingly simple. A popular open-source GitHub Action called tj-actions/changed-files had been quietly compromised. Here is how it worked. The attackers gained access to the repository hosting that Action and then did something sneaky. They went back and updated the version tags, which are labels like @v35 or @v44 that teams use to reference a specific version, to point at their malicious code instead of the original. No announcements. No pull requests. No alerts. Just a silent swap. Every team whose pipeline said “use version 44 of this Action” was now running the attackers’ code, and that code had one job: find every secret in your pipeline environment and write it to the logs.
其原因并非复杂的零日漏洞攻击,也不是国家级黑客攻破了 GitHub 的服务器,而是一个令人尴尬的简单原因:一个名为 tj-actions/changed-files 的流行开源 GitHub Action 被悄悄入侵了。攻击过程如下:攻击者获得了托管该 Action 的仓库访问权限,然后做了一个隐蔽的操作——他们修改了版本标签(即团队用来引用特定版本的 @v35 或 @v44 等标签),将其指向了恶意代码而非原始代码。没有公告,没有 Pull Request,没有警报,只是悄无声息的替换。每一个在流水线中配置了“使用该 Action 的 44 版本”的团队,现在运行的都是攻击者的代码,而这些代码只有一个任务:找出你流水线环境中的所有密钥并将其写入日志。
This vulnerability was assigned CVE-2025-30066. CVE stands for Common Vulnerabilities and Exposures, which is the official tracking system for publicly disclosed security flaws. It became the largest GitHub Actions supply chain attack on record. But here is the detail I want you to hold onto, because it is the heartbeat of this entire article. The teams that had pinned their Actions to a specific commit SHA were not affected. A commit SHA (Secure Hash Algorithm) is a unique cryptographic fingerprint of the exact code they had reviewed, and it cannot be faked or silently moved. One configuration decision separated the impacted from the protected. That single fact changed how I think about pipeline security. Let me explain why, and then walk you through the seven things you can do to protect your own systems.
该漏洞被编号为 CVE-2025-30066。CVE 代表“通用漏洞披露”,是公开披露安全漏洞的官方追踪系统。这成为了有史以来规模最大的 GitHub Actions 供应链攻击。但有一个细节我希望你记住,因为它是整篇文章的核心:那些将 Action 锁定(pinned)在特定提交 SHA(Commit SHA)上的团队并没有受到影响。提交 SHA(安全哈希算法)是他们所审查代码的唯一加密指纹,无法被伪造或悄悄移动。一个配置决策将受害者与受保护者区分开来。这一事实改变了我对流水线安全的看法。让我解释原因,然后带你了解保护自己系统的七个步骤。
This Was Not a One-Off
这并非孤立事件
Before I get into the solutions, I want to make sure you understand the scale of what is happening, because CVE-2025-30066 was a headline but it was not an outlier. In December 2024, Ultralytics, the company behind the YOLO (You Only Look Once) computer vision library, was hit by an almost identical attack. YOLO is one of the most widely used AI projects in the world with nearly 60 million downloads on PyPI (the Python Package Index, which is the main place people download Python libraries from). Attackers exploited a misconfigured workflow trigger called pull_request_target to run their own code inside Ultralytics’ pipeline. The result was a cryptominer, which is software that secretly uses your computer’s resources to generate cryptocurrency for someone else, bundled into four official releases and shipped to users around the world.
在进入解决方案之前,我想确保你了解当前形势的规模,因为 CVE-2025-30066 虽然上了头条,但并非个例。2024 年 12 月,YOLO(You Only Look Once)计算机视觉库背后的公司 Ultralytics 遭遇了几乎相同的攻击。YOLO 是世界上使用最广泛的 AI 项目之一,在 PyPI(Python 软件包索引,人们下载 Python 库的主要场所)上的下载量接近 6000 万次。攻击者利用配置错误的 pull_request_target 工作流触发器,在 Ultralytics 的流水线中运行了自己的代码。结果导致一个加密货币挖矿程序(一种秘密利用你的计算机资源为他人挖掘加密货币的软件)被捆绑进四个官方版本中,并分发给了全球用户。
In February 2026, Trivy, Aqua Security’s own open-source security scanning tool used by thousands of organisations to find vulnerabilities in their pipelines, had its GitHub Actions workflow exploited to steal an organisation-wide PAT (Personal Access Token) that had access to 33 internal workflows. The tool had been quietly vulnerable since October 2025. A separate scanner had even flagged the issue in November 2025, three months before an attacker found it first. When a security company’s own security tool gets compromised through its CI/CD (Continuous Integration and Continuous Deployment) pipeline, that tells you something important. This is not about negligence or inexperience. It is about a systemic gap in how the industry thinks about pipeline security.
2026 年 2 月,Trivy(Aqua Security 旗下的开源安全扫描工具,被数千家组织用于发现流水线漏洞)的 GitHub Actions 工作流被利用,导致一个拥有 33 个内部工作流访问权限的组织级 PAT 被窃取。该工具自 2025 年 10 月起就一直处于静默漏洞状态。甚至在 2025 年 11 月,另一个扫描器就已经标记了该问题,比攻击者发现它早了三个月。当一家安全公司的安全工具通过其 CI/CD(持续集成与持续部署)流水线被攻破时,这说明了一个重要问题:这并非疏忽或经验不足,而是行业在看待流水线安全方面存在系统性差距。
Across all of these incidents and others like them, three root causes appear again and again:
- Actions pinned to tags instead of commit SHAs, because tags can be silently changed to point anywhere.
- Misuse of the
pull_request_targettrigger, a workflow setting that accidentally grants fork contributors access to internal secrets. - Overly permissive
GITHUB_TOKENscopes, where the automatic credential GitHub provides…
在所有这些事件及类似事件中,三个根本原因反复出现:
- Action 锁定在标签(tags)而非提交 SHA 上,因为标签可以被悄悄修改指向任何地方。
- 滥用
pull_request_target触发器,这一工作流设置会意外地授予 Fork 贡献者访问内部密钥的权限。 - 过度宽泛的
GITHUB_TOKEN权限范围,即 GitHub 提供的自动凭据……