🏢 公司C档 · NaN分

开发者的钥匙,正在被批量顺走

··约1分钟阅读

📋 总体概括

GitHub Actions 恶意工作流与 npm 供应链投毒两起事件接连曝光:前者瞄准 2577 个密钥、确认窃取 26 个,后者一个包就跑了 3.7 万次下载。开发者流水线与依赖生态正在成为新的主攻击面,本文拆解攻击机理与防御路径。

📄 正文

一群黑客不再攻击你的服务器,而是安静地趴在你的 CI 流水线和 npm 依赖里,等你亲手把钥匙递过去。

最近披露的两起事件把这件事摆上了台面:一起是通过 GitHub Actions 恶意工作流窃取 SSH 私钥、云凭据和访问令牌;另一起是代号 MALFEX 的 npm 供应链投毒行动,一个伪装成工具包的恶意包累计下载超过 3.7 万次。两个案例,同一个逻辑——开发者,正在成为最好的跳板。

🔑 一行 YAML,偷走整个公司

想象一个再普通不过的开源贡献场景:外部开发者提交了一个 PR,仓库维护者的自动化工作流自动跑起来,名义上是一次"安全检查"。没人细看 workflow 文件里多出来的那几行。就在这几行里,环境变量被悄悄打包,发往了攻击者控制的服务器。

这就是本次 GitHub Actions 事件的核心剧本。攻击者将恶意逻辑伪装成安全检查类的工作流,目标直指三类高价值资产:SSH 密钥、云平台凭据、各类访问令牌。据 GBHackers 披露,这批恶意工作流瞄准了 2577 个 secrets。

但有一个关键细节值得单独强调:瞄准不等于得手。研究人员最终确认的成功外泄数量是——26 个 secrets,来自 13 个仓库。

指标数值说明
瞄准的 secrets2,577恶意工作流尝试触达的目标
确认外泄26"注入"与"执行"之间存在衰减
涉及仓库13成功窃取发生的实际范围

这个 2577:26 的比例,恰恰是理解此类攻击的关键。恶意工作流被注入,不等于恶意载荷被真正执行;执行了,也不一定能拿到 secrets 的运行时上下文。CI/CD 攻击有一条从"埋雷"到"起爆"的完整链路,每一环都有损耗:

产业逻辑在这里很清晰:仓库本身就是金库。现代研发流程里,云厂商的 Access Key、生产环境的部署私钥、第三方 SaaS 的令牌,大量以 GitHub Secrets 的形式托管在 CI 环境里。拿到一个仓库的 secrets,往往等于拿到了通往生产环境的一把门钥匙——甚至不用打任何一次传统意义上的"入侵"。

📦 一个 ASCII 艺术工具,藏了三年的贼

如果说 CI 攻击打的是"集中式金库",npm 投毒打的就是"毛细血管"。

MALFEX 是一个持续运营的 npm 供应链行动,通过 8 个恶意包分发针对 Windows 的恶意软件。据披露,背后疑似是一名单独运营者,从 2023 年 8 月起活跃至今——一个人,一条产线,干了两年多。

载荷配置也够"全家桶":远控木马 Overlord RAT、名为 movinlike 的信息窃取器,以及一个藏在 ASCII 艺术工具里的独立下载器。是的,一个帮你打印字符画的工具,顺手把你的浏览器保存密码、Discord 令牌和加密货币钱包一并打包带走。

贡献最大的包叫 function-flag,累计 37,419 次下载,且恶意代码从早期版本就已存在——不是某个版本被投毒,而是这个包"生而恶意",靠真实或刷量的下载量在生态里安家。

它的成本结构值得算一笔账。注册 npm 包几乎零成本,写一个"有点用"的小工具对熟练开发者只需几天,之后就是纯被动收割:每一个 npm install 都是一次自动投递。不需要钓鱼邮件,不需要绕过 EDR 的初始访问,受害者是自己把恶意代码拉进了开发环境,很多企业终端的安全软件反而因为"开发目录"的豁免策略而网开一面。

据多位接近开源安全社区的人士透露,这类单人小作坊式投毒在 npm 上"几乎是流水线生产",被下架一批,换个包名再来一批。审计与下架永远慢于注册与发布,这是结构性时差。

🎯 为什么攻击者集体转向开发者

金句先放这里: perimeter 早就没了,现在最软的边界是开发者的终端和流水线。

把两起事件放在一起看,会发现问题不是孤立的漏洞,而是一次攻击面的整体迁移。过去十年的安全建设,把网络边界、终端 EDR、邮件网关都加固了一遍,攻击者的性价比计算也随之改变:

右上方那两个点——CI/CD 凭据窃取和供应链投毒——正是这两起事件所处的位置。技术门槛不算最高(不需要 0day,只需要一次 PR 和一个 workflow 文件),回报却极高(一个 secrets 可能直通生产云环境;一台开发机上的浏览器密码和钱包文件,就是即取即用的现金)。

更深一层的原因是信任链的天然缺陷。开发者每天要做几十次信任决策:合并这个 PR、安装这个依赖、跑这个 CI 任务。安全机制如果要求每一次都人工审查,研发效率直接归零;如果不审查,攻击者就藏在效率的缝隙里。GitHub Actions 的 pull_request_target 类触发器、npm 缺乏强制代码审查的发布机制,都是这个矛盾的产物。

还有一个经常被忽视的事实:开发环境和生产环境的隔离,在大多数公司里只是纸面上的。开发机登录着云控制台,本地 .npmrc 里存着 registry token,SSH agent 里挂着多把生产密钥。攻击者偷一台开发机,等于偷了半个基础设施的地图和钥匙串。

🛡️ 从"信任代码"到"验证每一次执行"

好消息是,这两类攻击虽然隐蔽,防御抓手却相当具体。坏消息是,绝大多数团队还没做。

针对 CI/CD 场景,核心原则只有一条: secrets 不该出现在不需要它们的地方。落地动作包括:将 GITHUB_TOKEN 权限收敛到最小(默认只读、按 workflow 单独声明);用 OIDC 短时凭据联合认证替代长期存放的云 Access Key——令牌只在任务运行的那几分钟有效,偷走了也很快过期;对首次贡献者的 workflow 变更启用人工批准;开启 secret scanning 与推送保护,在密钥被提交前就拦截。

针对 npm 投毒,重点在"事前减面 + 事后止损":依赖数量本身就是攻击面,能不引入的包就不引入;新依赖进入 lockfile 前先过依赖审查,看下载量、维护者历史、发布时间线;构建环境做好出口管控——一个 ASCII 艺术工具没有任何理由往外发流量,这一条网络策略就能掐断 movinlike 的窃取链路。

开发者供应链防御清单
痛点 1
CI secrets 长期有效、权限过大
→
解法
OIDC 短时凭据 + 最小权限 GITHUB_TOKEN
痛点 2
外部 PR 自动触发特权工作流
→
解法
首次贡献者 workflow 变更强制人工审批
痛点 3
恶意依赖被顺手安装
→
解法
依赖审查 + 锁定 lockfile + 收敛依赖数量
痛点 4
窃取载荷外传无阻拦
→
解法
构建与开发环境出口管控、阻断陌生 C2
痛点 5
密钥泄露后发现太晚
→
解法
secret scanning / 推送保护 + 泄露应急轮换预案

把两起事件并排对照,还能看出攻防节奏上的差异:

维度GitHub Actions 事件MALFEX npm 行动
攻击载体恶意 workflow(伪装安全检查)8 个恶意 npm 包
主要目标SSH 密钥、云凭据、访问令牌浏览器密码、Discord 令牌、加密钱包
规模瞄准 2,577 secrets,确认外泄 26 个function-flag 单包 37,419 次下载
运营形态一次性注入 + 触发执行单人疑似运营,2023 年 8 月起持续
防御重心权限收敛、OIDC、工作流审批依赖审查、最小依赖、出口管控

一个值得注意的行业动向是: 软件供应链的可信证明(provenance、SBOM、签名验证)正在从合规议题变成工程议题。 当攻击者可以低成本伪造"一个正常的包"时,防御方的答案不能只是"更仔细地看",而是让每一次执行都可验证、每一把钥匙都短命、每一条出网流量都有理由。

小结

2,577 对 26,37,419 次下载对一个人的两年运营——这两组数字背后,是攻击者对开发者信任链的精准套利。CI 流水线和包管理生态不是"安全做得不够好",而是它们的设计前提(内部的人、可信的依赖)已经不成立了。对安全团队来说,下一个十年的攻防主战场不在DMZ,而在每一个 PR 和每一次 npm install。谁先把"验证每一次执行"做进流程,谁就先把这个新攻击面关小一半。

本文由本站 AI 辅助聚合生成,原始来源如下:

🔎 本文基于以下资讯(素材溯源 · 信息来源)

📰 相关阅读推荐(与本文相关的其他资讯)