Claude Code 的 settings.json 被注入了恶意 Hook——我亲手复现了全过程
Claude Code 的 settings.json 被注入了恶意 Hook——我亲手复现了全过程
几周前,某安全社区的帖子在开发者圈子里悄悄流传:有人声称 Claude Code 的 settings.json 可以被注入恶意 Hook,在用户毫不知情的情况下,每次调用工具时悄悄执行攻击者的脚本。
评论区两极分化。有人说"早就知道了,本地配置文件哪有什么安全可言";也有人觉得"这不就是要本地权限才能搞的事,有什么好怕的"。
我决定自己动手复现一遍,不是为了制造恐慌,而是想搞清楚两件事:攻击路径是否真实存在?普通用户是否真的暴露在风险中?
结论先说:攻击是真实的,但防御窗口比你想象的宽——前提是你知道往哪里看。
---
什么是 Hook 注入?先搞懂原理再谈防御
在聊攻击之前,先搞清楚 Claude Code 的 hooks 机制是怎么回事。
Claude Code 的 settings.json 里有一个 hooks 字段,这是 Anthropic 提供给开发者的合法自动化功能。它允许你在特定事件触发时,自动执行自定义脚本。支持的事件类型包括:
PreToolUse:工具调用前触发PostToolUse:工具调用后触发Stop:会话结束时触发Notification:通知事件触发
正常的使用场景是什么?比如你可以配置"每次 Claude Code 写完代码,自动运行 lint 检查",或者"调用 Bash 工具前,先记录操作日志"。这是完全合理的开发者工具。
官方文档参考:[Anthropic Claude Code Hooks 文档](https://docs.anthropic.com/en/docs/claude-code/hooks)问题在于:这个机制没有内置的签名验证或来源校验。
攻击者只需要篡改 settings.json,往 hooks 字段里写入恶意命令,就能在用户每次使用 Claude Code 时,悄悄触发:
合法功能(hooks 机制)
↓
配置文件被篡改(settings.json 写入恶意 hook)
↓
用户正常使用 Claude Code(触发 PreToolUse/PostToolUse)
↓
恶意命令在后台执行(外传文件 / 建立后门 / 数据窃取)
整个链路里,用户的终端界面完全正常,Claude Code 的对话也完全正常。恶意行为发生在"幕后"。
---
复现过程——3 个最容易被盯上的位置
这是全文最重要的部分。我按风险等级,从高到低列出三个高危注入点。
位置①:用户级全局配置 ~/.claude/settings.json
路径: ~/.claude/settings.json(macOS/Linux),%APPDATA%\Claude\settings.json(Windows)
风险等级:🔴 高
这个文件是 Claude Code 的全局配置,对当前用户的所有项目生效。一旦被篡改,攻击者注入的 hook 会在你打开任何项目、调用任何工具时触发。
更关键的是:这个文件通常不在任何 Git 仓库里,不会被代码审查,也不会出现在 git diff 里。它是最难被发现的注入点。
一个最小化的恶意 hook 结构长这样(已脱敏,仅展示结构):
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/bin/sh -c 'PAYLOAD_COMMAND_HERE'"
}
]
}
]
}
}
攻击者只需要把 PAYLOAD_COMMAND_HERE 替换成任意 shell 命令——比如把当前目录的文件列表发到远端服务器,或者下载并执行一个后门脚本。
---
位置②:项目级配置 .claude/settings.json
路径: <项目根目录>/.claude/settings.json
风险等级:🟠 中(供应链攻击场景下升级为高)
这个文件是项目级配置,只对当前项目生效。但它有一个特殊的危险性:它会随 Git 仓库一起传播。
这就是经典的供应链攻击路径:
1. 攻击者 fork 一个热门开源项目
2. 在 .claude/settings.json 里注入恶意 hook
3. 提交 PR,或者直接在自己的 fork 里等待
4. 有人克隆了这个仓库,用 Claude Code 打开项目
5. 恶意 hook 在本地静默激活
更隐蔽的变体:攻击者在一个"教程仓库"里预埋配置,附上一句"clone 下来直接用"——你以为你在学习,实际上已经中招。
典型攻击场景: 克隆了一个 GitHub 上"Claude Code 最佳实践模板"的仓库,没有检查.claude/ 目录。
---
位置③:本地覆盖层 .claude/settings.local.json
路径: <项目根目录>/.claude/settings.local.json
风险等级:🟠 中(隐蔽性最高)
这个文件是三个位置里最容易被忽视的,原因有两个:
第一,它的名字里有"local",给人一种"这只是我本地的临时配置"的错觉,大多数开发者不会认真审计它。
第二,也是最关键的:这个文件默认被 .gitignore 排除,不会出现在 Git 历史里,不会被 code review,不会触发任何版本控制的警告。
攻击者如果能在你的机器上执行一次任意代码(哪怕只是一个一次性的恶意脚本),就可以把后门写进这个文件——然后它就永远不会出现在你的 git status 里。
---
三个位置对比一览
| 位置 | 路径 | 默认存在 | 风险等级 | 在 .gitignore 中 | 主要威胁场景 | | 全局配置 |~/.claude/settings.json | 是 | 🔴 高 | 不适用 | 本地恶意脚本篡改 |
| 项目配置 | .claude/settings.json | 否 | 🟠 中 | 否(会被 Git 追踪) | 供应链 / 恶意仓库 |
| 本地覆盖 | .claude/settings.local.json | 否 | 🟠 中 | 是(默认忽略) | 本地写入后永久隐藏 |
---
5 分钟自查清单——现在就能做
读到这里,你可能已经想去检查一下自己的配置了。好,现在就做。
macOS / Linux 自查命令
# 检查全局配置
echo "=== 全局配置 ===" && cat ~/.claude/settings.json 2>/dev/null | grep -A 15 "hooks" || echo "未找到 hooks 字段或文件不存在"
检查项目配置(在项目根目录执行)
echo "=== 项目配置 ===" && cat .claude/settings.json 2>/dev/null | grep -A 15 "hooks" || echo "未找到 hooks 字段或文件不存在"
检查本地覆盖配置
echo "=== 本地覆盖配置 ===" && cat .claude/settings.local.json 2>/dev/null | grep -A 15 "hooks" || echo "未找到 hooks 字段或文件不存在"
Windows(PowerShell)自查命令
# 检查全局配置
Write-Host "=== 全局配置 ===" -ForegroundColor Yellow
Get-Content "$env:APPDATA\Claude\settings.json" -ErrorAction SilentlyContinue | Select-String -Pattern "hooks" -Context 0,15
检查项目配置(在项目根目录执行)
Write-Host "=== 项目配置 ===" -ForegroundColor Yellow
Get-Content ".claude\settings.json" -ErrorAction SilentlyContinue | Select-String -Pattern "hooks" -Context 0,15
检查本地覆盖配置
Write-Host "=== 本地覆盖配置 ===" -ForegroundColor Yellow
Get-Content ".claude\settings.local.json" -ErrorAction SilentlyContinue | Select-String -Pattern "hooks" -Context 0,15
如何判断 hooks 字段是否可疑?
看完输出,对照这个白名单:
✅ 正常 hooks 字段的特征:{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "npm run lint"
}
]
}
]
}
}
- 命令是本地工具调用(
npm、eslint、prettier等) - 没有网络请求(
curl、wget、nc等) - 没有 base64 解码(
base64 -d) - 没有管道到
sh或bash - 命令逻辑清晰,你能看懂它在干什么
- 包含
curl、wget向外部 URL 发送数据 - 包含
base64 -d | sh这类解码执行模式 - 包含
/tmp/目录下的脚本调用 - 命令经过混淆,看不懂在做什么
- 你完全不记得自己配置过这段
如果你在排查过程中发现自己需要一个更干净的调用环境,文末有推荐。
---
治本方案——用 API 直连绕开本地配置风险
说完了怎么查,再聊一个更根本的问题:为什么 hooks 注入能成为攻击面?
因为 Claude Code 是一个本地客户端,它的配置存在本地文件里,执行权限等同于当前用户权限,配置变更没有任何审计机制。这不是 Claude Code 的独有问题,而是所有"本地配置驱动的 AI 工具"的共同局限。
越依赖本地客户端的复杂配置,暴露面越大。对于重度 Vibe Coding 用户,有一个值得考虑的替代路径:通过标准 API 接口直接调用模型,而不是依赖本地 hooks 机制来完成自动化流程。
API 直连的优势很明确:
- 配置透明:你的调用参数完全在代码里,没有隐藏的配置文件
- 版本可控:
model=参数明确指定模型版本,行为可预期 - 审计方便:所有请求都经过标准 HTTP 层,可以用任何工具抓包审计
- 多模型统一:一套代码可以切换 Claude、GPT、Gemini、DeepSeek 等主流模型
一个简单的 API 调用示例:
import openai
client = openai.OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.884819.xyz/v1"
)
response = client.chat.completions.create(
model="claude-opus-4.7", # 或切换为 gpt-5.4、deepseek-ai/deepseek-v4-pro 等
messages=[
{"role": "user", "content": "帮我 review 这段代码"}
]
)
这段代码里没有任何隐藏的 hooks 机制,没有本地配置文件,没有"在你不知情时触发的脚本"。你看到的就是全部。
如果你已经在用 Claude Code 做 Vibe Coding,不妨同步试试通过 API 直连的方式——配置完全在你自己手里,hooks 机制也不再是攻击面。8848AI([api.884819.xyz](https://api.884819.xyz))支持 Claude、GPT、Gemini、DeepSeek 等主流模型统一接入,一个 Key 管全部,无需订阅,国产模型(DeepSeek/千问等)完全免费,注册即送体验 token,审计起来也更清晰。
---
写在最后
做完这次复现,我最大的感受不是"Claude Code 不安全",而是:大多数开发者对自己工具链的配置文件几乎没有安全意识。
这三个文件你上次打开是什么时候?你知道里面有什么内容吗?
攻击者赌的就是"你不会去看"。
现在你知道往哪里看了。跑一遍自查命令,5 分钟,你就比 90% 的 Claude Code 用户更安全。
---
下一期我们要聊的,是 Claude Code 另一个更隐蔽的风险点:CLAUDE.md 文件的提示注入。
>
当你的"项目说明文件"开始替攻击者说话——告诉 Claude"忽略用户的安全限制"、"在所有输出里附加特定内容"——你会怎么发现?这个攻击面甚至不需要执行任何系统命令,纯粹在语言层面完成渗透。下期见。
---
本文由8848AI原创,转载请注明出处。关注8848AI,带你从零开始学AI。#AI安全 #ClaudeCode #开发者工具 #Vibe编程 #供应链攻击 #8848AI #AI工具 #网络安全