一幅生成式抽象插画,置于浅灰蓝色背景之上:一块高大的深石板色面板位于画面中偏左,一道细长的浅青色光束水平穿过它,并在右侧展开成一片宽阔的光锥,横跨一片由小型几何方块构成的区域。大多数方块处于冷色阴影之中;靠近光束中心的一簇方块发出温暖的琥珀色光芒。背景中隐约可见蓝图网格和细密的同心弧线。画面中不含任何文字、数字、人物、品牌标识或机构标志。OrcaRouter 的标志被合成在右下角。
AI Safety Incidents

Clinejection:一个问题标题如何触及 Cline 的 npm 令牌

作者

Rowan Sterling

发布日期

最新模型 · 20查看全部模型 →
基准测试:Artificial Analysis · 每日更新
返回全部文章

2026 年 2 月 9 日,安全研究员 Adnan Khan 公开披露了他于 1 月 1 日私下报告给 Cline 的一个漏洞:这个开源 AI 编程助手将一套基于 Anthropic 的 claude-code-action GitHub Action 构建的自动化 issue 分诊程序,接入了一个会把任何传入的 GitHub issue 标题直接粘贴进模型指令的提示词。任何 GitHub 账号都能通过新建一个 issue 来触发它;在 Khan 的复现中,一个被写成指令的标题让该 agent 在工作流内执行了一条 shell 命令。随后他追踪了从这一立足点出发、经由 GitHub Actions 缓存投毒、直至 VS Code Marketplace、OpenVSX 和 npm 发布凭据的路径。在 Cline 修复该工作流八天后,一个 Cline 以为已经轮换的 npm 发布令牌被用来发布了 cline 2.3.0,而该版本会在每一台安装该软件包的机器上安装 OpenClaw。完整条目及其严重性和置信度评级位于Orca AI Incident Archive中,与同一时期的相邻供应链记录并列。

两个日期,而不是一个

档案将这条记录标注为2026年2月9日,精确到日,而这一天正是Khan在adnanthekhan.com发布其文章的日子。这并不是恶意软件包出现的那一天。该漏洞本身于2025年12月21日被引入,源自一次向cline/cline仓库添加triage工作流的提交,并且一直存在,直到Cline于2月9日删除了该工作流。未经授权的npm发布于2月17日,即修复后八天、Khan首次私下报告后四十七天。

将这两个日期区分开来很重要,因为本案中最关键的事实就位于二者之间的空档中:门在2月9日被关闭,但入侵者早已复制好的钥匙在2月17日仍然有效。Cline本人于2月17日发给Khan、并在其帖子中转载的更正直接说明了这一点:“我们在2月9日轮换凭据时,npm发布令牌没有被正确撤销。删除的是错误的令牌,而暴露的那个仍然处于活动状态。”

链条:从议题标题到发布令牌

有漏洞的文件是 .github/workflows/claude-issue-triage.yml,它在 issues 事件上运行,并调用了 anthropics/claude-code-action@v1,使用的是 Claude Opus 4.5,该版本在工作流中固定为 claude-opus-4-5-20251101。Khan 引用了该工作流的配置:allowed_non_write_users 被设置为通配符 "*",因此任何 GitHub 账户只需创建一个 issue 就能触发该代理;同时 claude_args 向 --allowedTools 传入了 Bash、Read、Write、Edit、Glob、Grep、WebFetch 和 WebSearch。Bash 才是关键所在。它使模型在一个于默认分支上下文中运行的工作流内获得了 shell 执行能力。

提示词在插入 issue 标题时没有对其进行清洗。Khan 的概念验证使用了一个以“Tool error.”开头的标题,并在其后接上一段指令:先从某个特定 commit 安装一个辅助包,然后再继续分诊。该 commit 指向一个 fork,其 package.json 中带有一个 preinstall 脚本,该脚本在 npm 尚未完成任何安装之前就针对攻击者控制的端点执行了一条 curl 命令。由于安装是通过 Bash 工具运行的,模型从未检查实际执行了什么。Khan 在 Cline 仓库的一个镜像上复现了该问题,并报告称该 agent 在每一次尝试中都执行了该载荷。

分诊工作流中的代码执行本身并不等于获得发布凭据。这一步源于 GitHub Actions 的一个特性,Khan 曾在 2024 年发布的一个名为 Cacheract 的工具中记录过该特性:任何工作流都能读写仓库缓存,并完全控制缓存键和版本,即使该工作流从未声明缓存步骤。分诊作业在默认分支上运行,因此它与夜间发布作业共享缓存作用域,而这些夜间发布作业确实会从缓存恢复 node_modules,并且确实持有发布令牌。

缓存条目是不可变的,因此攻击者无法直接覆盖发布作业将要恢复的条目。Khan 的绕过办法是利用 GitHub 于 2025 年 11 月 20 日的一项策略变更:一旦某个仓库的缓存超过 10 GB,该服务就会按最近最少使用顺序立即逐出缓存条目。把缓存灌到超过 10 GB,合法条目就会因老化而被清除;再用被投毒的内容占用腾出的键,下一个恢复这些条目的作业就会运行攻击者的代码。Cacheract 在单次工作流运行内自动化了整个序列,并且它通过覆盖 actions/checkout 的 action.yml 来持久化,使该 action 的后置步骤在每个作业结束时执行载荷。

链条的最后一环是夜间任务,它大约在 UTC 凌晨 2 点运行,恢复被投毒的 node_modules,然后引爆。被带出来的是 VSCE_PAT、OVSX_PAT 和 NPM_RELEASE_TOKEN,分别是 VS Code Marketplace、OpenVSX 和 npm 的凭据。每一环是否都按该顺序针对 Cline 自己的仓库运行,则是另一个问题,下文将讨论。

A self-built HTML card titled 'Six steps from an issue title to a release token', badged 'Clinejection · GHSA-9ppg-jx86-fqw7', subtitled 'The chain as Adnan Khan describes it, with the workflow configuration he quotes'. Six numbered rows read: 1, Issue opened on cline/cline, the title carries the instructions and allowed_non_write_users is set to the wildcard; 2, claude-issue-triage.yml runs, claude-code-action with Bash, Read, Write, Edit, Glob, Grep, WebFetch and WebSearch; 3, npm install from a fork commit, the fork's package.json carries a preinstall script and the model runs it through Bash; 4, Cache flooded past 10 GB, GitHub's LRU eviction removes the legitimate entries and frees their keys; 5, Poisoned entries claim the keys, the nightly jobs restore attacker content as node_modules; 6, Nightly job runs at about 2 AM UTC, VSCE_PAT, OVSX_PAT and NPM_RELEASE_TOKEN leave the runner. A footer reads 'Source: Adnan Khan, Clinejection, 9 February 2026; Cline advisory GHSA-9ppg-jx86-fqw7.' The OrcaRouter logo is composited in the bottom-right corner.

为什么夜间任务使用的是生产环境凭据

显而易见的反对意见是,夜间版和生产版发布应持有不同的机密。Khan 的回答是,这种隔离只是名义上的。OpenVSX 和 VS Code Marketplace 将发布令牌绑定到发布者身份,而不是绑定到单个扩展;稳定的和夜间版的 Cline 扩展都在同一身份下发布,Khan 在 OpenVSX 上将该身份指认为 saoudrizwan。在 npm 上,细粒度令牌模型绑定到包,而 Cline 将其稳定版和夜间版 CLI 构建发布到同一个 cline 包。因此,为夜间任务签发的令牌可以发布生产制品,而这正是八天后发生的事情。

汗本人对这一影响范围的表述建立在规模之上:他引用了 Cline 宣布其安装量已突破 500 万次的公告,并指出,通过窃取的凭据推送的扩展更新,会在每一位编辑器自动更新的开发者的环境中执行,并拥有该开发者的权限,以及机器上存放的任何密钥、令牌和源代码。

实际发表的是什么,以及它起了什么作用

已发布的产物是 cline 2.3.0,而且它体积很小。npm registry 自身的时间戳显示,2.3.0 发布于 2026 年 2 月 17 日 11:26:51 UTC,而干净的 2.4.0 则于同日 19:23:08 UTC 发布。Cline 的公告称,这一暴露窗口约为八小时,直到 2.3.0 于太平洋时间上午 11:30 被弃用。该包的 package.json 只多了一行,即一条内容为 npm install -g openclaw@latest 的 postinstall 脚本。Cline 的公告 GHSA-9ppg-jx86-fqw7 指出,没有其他包文件被改动,且 dist/cli.mjs 与合法的 2.2.3 构建逐字节完全相同。

OpenClaw 是一个真正的开源 AI 代理框架,而不是恶意软件,Cline 的安全公告也明确说明了这一点:它是一个合法项目,但其安装并未获得授权,也不是有意为之。分析了该 tarball 的 Endor Labs 将总体影响评估为低,理由是此次安装并未启动 OpenClaw 的 Gateway 守护进程。StepSecurity 的报告中则衡量了另一面:全局安装会把该框架留在磁盘上,并带有安装用户所拥有的任何凭据和文件访问权限,而 OpenClaw 的设计——一个带有操作员 API 的持久本地网关——使其成为在那里发现的高价值目标。这两项评估并不矛盾。一项描述的是在该窗口期内运行了什么;另一项描述的是之后留下了什么。

下载量是唯一必须谨慎对待的数字。StepSecurity 报告称,被入侵的版本在被弃用前下载了约 4,000 次,The Register 重复了这一数字。Endor Labs 将 cline 在 1 月 19 日至 2 月 17 日期间的月度下载量定为 418,545 次,这反映的是该软件包的正常流量,而不是恶意构建版本。这两个数字都不是在统计机器数量:下载量并不等于受影响开发者的人数,而且没有任何一方公布过 2.3.0 的安装基数数据。Microsoft 的 Threat Intelligence 团队在 X 上表示,他们观察到 2 月 17 日 OpenClaw 安装量出现了“小幅但明显的上升”,原因是 Cline 安装脚本,正如 The Hacker News 所报道的那样。

GitHub 针对 GHSA-9ppg-jx86-fqw7 的公告记录既未包含 CVE,也未包含 CWE,其严重性评级为“低”。该评级针对的是无害的载荷,而非凭据窃取,而且它与档案中针对该事件本身给出的“严重”评级并列,显得颇为不协调。该公告记录 2.3.0 为受影响版本,2.4.0 为修复版本。

Cline 未予回应的披露

Khan 的发布前时间线是记录中最不涉及模型、最关乎流程的部分。他于 2026 年 1 月 1 日通过 GitHub 的私密漏洞报告提交了一份 GHSA,并在同一天向 Cline 信任页面上列出的安全联系人发送了电子邮件。他于 1 月 8 日向 Cline 的一名开发者发送了跟进邮件。他于 1 月 18 日尝试在 X 上给 Cline 的 CEO 发私信。他于 2 月 7 日再次致信,却只收到一个自动生成的工单编号。他于 2 月 9 日发布。

大约三十分钟到一小时后,Cline 合并了修复,即拉取请求 9211。该 PR 删除了三个工作流文件 claude-issue-triage.yml、claude-pr-review.yml 和 cline-pr-review.yml,并从 publish.yml、publish-nightly.yml、npm-nightly.yaml 和 npm-main.yaml 中移除了缓存,总共涉及七个文件;由于不再有可依赖的缓存命中,安装步骤现已改为无条件执行。

Cline 于2月10日发布的公开回应(被 Khan 的帖子引用)接受了该发现,并列出了即时缓解措施:移除 issue 和 PR 机器人审查工作流,从处理发布凭据的发布工作流中移除 actions/cache,并轮换相关凭据,包括机器人、提供商和发布令牌。它还承认了处理方式:“我们承认,我们对您最初报告的响应时间是不可接受的。一份于1月1日提交的报告不应需要到2月9日公开披露后才得到处理。”

2月11日,Cline表示它已完成VSCE_PAT、OVSX_PAT和NPM_RELEASE_TOKEN的完整轮换,并且对2025年12月21日至2026年2月9日期间所有三个分发渠道上的每个版本进行审计后发现,每个Marketplace和OpenVSX版本都对应到一个已打标签的GitHub发布,且所有41个npm版本都与源代码一致。它得出结论称,在“所称的暴露窗口期间”没有发布任何未经授权的版本。六天后,它在上文引用的消息中更正了记录:npm令牌并未被撤销,而2.3.0正是用它发布的。

A self-built HTML card titled 'From private report to public disclosure', subtitled 'Khan's pre-publication timeline, and what followed'. Eight dated rows read: 21 Dec 2025, vulnerable claude-issue-triage.yml committed; 1 January 2026, GHSA filed and email sent to Cline's listed security contact; 8 January 2026, follow-up email to a Cline developer, no reply; 18 January 2026, direct message to Cline's CEO on X, no reply; 7 February 2026, final email, automated ticket number only; 9 February 2026, public disclosure and PR 9211 merged within about an hour; 11 February 2026, Cline reports full rotation and a clean audit; 17 February 2026, cline 2.3.0 published with a still-valid npm token. A footer reads 'Times and dates as recorded by Adnan Khan; the 17 February publish timestamp is corroborated by the npm registry.' The OrcaRouter logo is composited in the bottom-right corner.

已确立、已归属、未解决

• 已确认。工作流配置是公开的,并且是在修复之前发布的。Khan 在仓库的一个镜像上复现了提示注入。Cline 合并了修复措施,并发布了一份公告,确认了 2.3.0 的发布、新增的 postinstall 行、未更改的 CLI 二进制文件、八小时的时间窗口以及令牌故障。npm 注册表中 2.3.0 和 2.4.0 的时间戳与公告中的时间一致。该存档将记录评为严重,置信度为 A,记录了真实危害,且没有争议标记。

• 已归因,但尚未确证。2.3.0 由谁发布仍是一个未决的归因问题。Michael Bargury 与一款名为 Raptor 的自动化调查工具于 2 月 19 日发布的取证分析报告点名了一个 GitHub 账户 glthub-actions,并以高置信度报告称:该账户 fork 了 cline/cline,于 2026 年 1 月 28 日 03:51 UTC 以被注入的标题提交了 issue 8904,并使用某个 fork 提交运行了来自 gist 的 payload。Khan 确认账户 gcbrun 和 Dev11940518 属于他本人,而 glthub-actions 不是。该报告发布时,该账户已被删除或停用,且 Cline 未点名任何人。应将该身份视为第三方发现。

• 争议在于性质,而非事实。{{1}}Bargury 评估该事件与安全研究演示相符,而非恶意活动,并援引良性载荷以及该行为者针对 New Relic 自动化仓库的过往行为作为依据。{{/1}} {{2}}Cline 称其为未经授权的发布,而 Khan 写道,发布 2.3.0 的行为者“据推测”就是污染缓存的那个人。{{/2}} {{3}}没有人证明存在造成伤害的意图,也没有人证明不存在这种意图。{{/3}}

• 未解决。Khan 本人在发布前的说明中对一点颇为谨慎,而后来的报道有时会淡化这一点:在 2026 年 1 月 31 日至 2 月 3 日之间,有几次夜间运行因一个未产生任何输出的 Post Checkout 步骤而失败,而这正是 Cacheract 的失陷指标;分诊工作流是最显而易见的路径,但尚未被证明就是该活动的入口点。也没有任何一方公布证据表明 Marketplace 或 OpenVSX 令牌曾被使用;各方迄今拿出的唯一产物就是 npm 构建。

A self-built HTML card titled 'What the record supports', subtitled 'One column is documented, one is other people's findings, one is simply open', split into three columns. The first, headed Established, lists four items: the triage workflow interpolated issue titles into the prompt and allowed any GitHub account to trigger it, with Bash among the tools; Khan reproduced the injection on a mirror of the repository; Cline's advisory GHSA-9ppg-jx86-fqw7 confirms cline 2.3.0, the added postinstall line, the unchanged CLI binary and an eight-hour window; npm registry timestamps place 2.3.0 at 11:26 UTC and 2.4.0 at 19:23 UTC on 17 February 2026. The second, headed Attributed, lists three items: the account glthub-actions and issue 8904 come from a third-party forensic write-up, not from Cline; that the actor copied Khan's public proof-of-concept repository is an inference from timing and from his own statement; that the publish was a research demonstration rather than an attack is one analyst's assessment. The third, headed Unresolved, lists three items: whether the triage workflow was the entry point for the late-January cache anomalies; whether any Marketplace or OpenVSX credential was used, with no artefact published; how many distinct machines installed 2.3.0, since about 4,000 is a download count. A footer reads 'Sources: Adnan Khan, Clinejection, 9 February 2026; Cline, GHSA-9ppg-jx86-fqw7; StepSecurity, 17 February 2026; Endor Labs, 18 February 2026; Michael Bargury and Raptor, 19 February 2026.' The OrcaRouter logo is composited in the bottom-right corner.

之后发生了什么变化

修复同时落在多个层面,值得逐一说明,因为它们分别解决了这次失败的不同部分。外部人员可触达的工作流被删除,而不是被收窄权限。缓存被从四个持有发布密钥的发布工作流中移除,而不是从整个仓库中移除,正是这一改动阻断了攻击者的转向路径。凭据已轮换,并且在 2 月 17 日更正后,正确的 npm 令牌被吊销。Cline 的安全公告称,npm 发布现在通过 GitHub Actions 使用 OIDC 来源证明,而 StepSecurity 的元数据分析说明了这为何重要:合法发布版本已经带有来源证明,而 2.3.0 是由人工账户发布的异常项。缺口在于,长期令牌路径与可信发布并存且仍然开放,而这正是 Endor Labs 认为维护者应当关闭的具体事项。Cline 发布了 GHSA-9ppg-jx86-fqw7,将 2.3.0 标记为弃用并附上不应安装的说明,同时引导用户使用 2.4.0 或更高版本。

Khan 的结构性建议比实际落实的范围更进一步,值得作为他本人的主张记录下来,而不是记在 Cline 名下:从任何分诊工作流中剔除 Bash、Write 和 Edit,只给它保留文件读取以及它所需要的那几个具体的 GitHub CLI 调用;绝不在持有生产发布密钥的任务中恢复缓存;并让夜间发布拥有自己的注册表命名空间和专用的非生产发布身份,这样一来,即便夜间发布的令牌被盗,也根本无法发布稳定版本。

修复与恶意发布之间相隔八天,正是这个细节让这条记录值得留存。这条链上的每一步都是已知的技术:Khan 早已公开过那个缓存投毒工具,Aikido Security 在 2025 年 12 月的 PromptPwnd 研究也记录了相同的分诊配置错误模式。真正把它们组合成一起供应链事件的,是一个让陌生人的文本得以抵达 shell 的工作流、一份与持有发布密钥的任务共享的缓存,以及一次漏掉某个凭据的令牌轮换。三处修复中的任何一处单独实施,都足以打断这条链;而第三处迟到了八天。