/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
今天刷到一条让我手一抖的帖子:Claude Code 联网查资料、跑 curl 的时候,会把你的登录邮箱写进请求头的 User-Agent,发给 Wikipedia、美国证券交易委员会(SEC)这类站点。GitHub 上的相关 issue 在 Hacker News 上冲到了一千多分。
结论先放前面:
一、到底发生了什么
先把时间线捋清楚(时间换算成北京时间):

- 11 月 3 日:Claude Code 2.1.317 发布,更新日志里有一行:新增检查,在 web 或 shell 工具调用要把你的账号邮箱发到网络之前先询问。
- 11 月 6 日 06:13 前后:有开发者在 GitHub 提了 issue,自述版本 2.1.318、macOS,说每天收到几十封诈骗邮件,怀疑是 Claude Code 把邮箱交给了第三方。邮件和泄露之间的因果是他本人的说法,没有独立证据;评论里也有人用邮箱别名、用了几个月没收到垃圾邮件。相关不等于因果,别一看到垃圾邮件就归到这件事上。
- 同一天:Claude Code 团队成员在 issue 和 Hacker News 上回复:这不是谁实现的“功能”;Wikipedia 这类站点要求脚本客户端自报家门,模型就把上下文里的账号邮箱填进了 User-Agent;下个版本(据说下周初)会把账号邮箱从上下文里拿掉;稳定通道当时还停在 2.1.311,要升到 2.1.317 或更高。他原话里有一句:“我们本该更早发现这个行为。”
据报道,类似反馈 7 月就有人提过,这次不是第一次被注意到。
二、为什么模型会这么干
把链条画出来其实很朴素:

有个细节很有意思:2.1.234(8 月 17 日)的更新日志已经写过——“告诉 Claude 账号邮箱只用于识别你,不要发给无关服务,除非你要求”。文字叮嘱早就有,这次还是漏了。 靠提示词约束模型永远只是“请求”,真要兜底,得靠不经过模型的确定性检查。
另有传言说“SEC 强制要邮箱”,Hacker News 上有人实测换成别的非 curl User-Agent 也能过,所以我只当线索,不下结论。
三、官方补丁到底拦了什么
内置的补丁叫 cc-plugin-privacy,默认开启,可以在 /plugins 里关掉。它的源码和 README 是公开的,我对着 README 整理了一张表:

一句话概括:只有“一条命令里同时出现你的账号邮箱和 User-Agent 写法(比如 curl -A、wget -U)”才会被拒。 邮箱放在网址里、请求体里、From 头里,或者通过变量、脚本、命令替换拼出来,补丁不管;WebFetch、WebSearch 和 MCP 工具,补丁不检查。README 自己的总结是“a courtesy, not a boundary”——一种礼貌,不是边界。
两点说明:
- 措辞不一致:更新日志写“先询问”,README 写“直接拒绝并让模型去掉邮箱重跑”。我按 README 理解,不影响结论。
- 有用户反馈补丁没生效:GitHub 上有人在 macOS 和 Windows 用不联网的 echo 命令测试,说 2.1.318 里补丁已加载但没拒绝;也有人说 /plugins 里看不到它。都是用户自述,官方未确认,所以别只信补丁,自己验一遍。
四、3 分钟自查(照做就行)

第 1 步:升级并确认版本。
claude update
claude –version
目标是 2.1.317 或更高。团队说的“移除上下文里的邮箱”要等下一个版本,到时候再升一次。
第 2 步:看补丁有没有开。 进入 Claude Code,输入 /plugins,在已安装列表里找 cc-plugin-privacy(内置,应显示已启用)。找不到也别慌,继续做第 3 步和后面的 hook,那才是你自己说了算的部分。
第 3 步:翻本地日志,看有没有已经发生过。 Claude Code 的会话转录以 JSONL 存在 ~/.claude/projects/ 下,账号邮箱存在 ~/.claude.json 里。下面这段只读命令,在 macOS、Linux 或 Windows 的 Git Bash/WSL 里都能跑(需要先装 jq):
EMAIL=$(jq -r '.oauthAccount.emailAddress' ~/.claude.json)
PAT='(user-agent|curl[^"]{0,40} -A|wget[^"]{0,40} -U)'
grep -rhoiE ".{0,80}${PAT}.{0,160}" –include='*.jsonl' ~/.claude/projects \\
| grep -iF -e "$EMAIL" -e "${EMAIL//@/%40}" | cut -c1-200
它列出“邮箱和 User-Agent 写法出现在同一段”的记录。我在自己构造的模拟转录上跑过:大小写不同、百分号编码的邮箱都抓到了,普通的 User-Agent: Mozilla 和单纯提到邮箱的聊天没有误报。真实日志可能有漏网或误报,命中了就当线索,自己打开那一行看发给了谁。
第 4 步:命中了怎么办? 先看是哪类站点:你自己要求访问的接口,影响有限;没印象的站点,就把这个邮箱当“已经公开”处理,留意钓鱼邮件,别拿它当重要账号唯一的恢复邮箱。别把邮箱本身贴到评论区。
五、想要确定性拦截:自己加一个 hook
Claude Code 的 PreToolUse hook 在工具调用执行之前运行,退出码 2 就是拦截——这条路不经过模型,所以和上面“提示词叮嘱”是两码事。官方文档里的写法就是这样:脚本从标准输入读 JSON,对 Bash 来说,命令字符串在 tool_input 的 command 字段里。
先把脚本存成 ~/.claude/hooks/no-email-leak.sh,再 chmod +x:

#!/bin/bash
# ~/.claude/hooks/no-email-leak.sh (PreToolUse hook)
EMAIL=$(jq -r '.oauthAccount.emailAddress // empty' ~/.claude.json)
[ -z "$EMAIL" ] && exit 0
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name')
BODY=$(echo "$INPUT" | jq -c '.tool_input' | tr 'A-Z' 'a-z')
E=$(echo "$EMAIL" | tr 'A-Z' 'a-z')
case "$BODY" in
*"$E"*|*"${E//@/%40}"*) ;;
*) exit 0 ;;
esac
if [[ "$TOOL" != "Bash" ]] || echo "$BODY" | grep -Eq 'user-agent|curl|wget|://'; then
echo "Blocked: account email must not appear in network requests" >&2
exit 2
fi
exit 0
再在 ~/.claude/settings.json 里注册(如果文件里已经有 hooks,把 PreToolUse 作为同级的键并进去,别整段覆盖):
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|WebFetch|WebSearch|mcp__.*",
"hooks": [
{ "type": "command", "command": "\\"$HOME\\"/.claude/hooks/no-email-leak.sh" }
]
}
]
}
}
逻辑很直白:工具输入里出现你的账号邮箱(不分大小写,也认百分号编码),并且是联网类工具,或是带 curl、wget、网址、User-Agent 字样的 Bash 命令,就拦下。不带联网字样的 git config user.email 之类不会被误伤。
怎么验证它生效了? 进会话,让 Claude 执行下面这条(它不会真的联网,GitHub 上的用户也是这么测补丁的),应该看到被拦截:
echo 'User-Agent: 你的邮箱' > /dev/null
我用模拟账号和 7 种输入测了脚本逻辑:大小写不同、百分号编码、WebFetch 里的邮箱都拦住了,别人的邮箱、普通 curl、不带联网字样的 git 命令都放行。但我没有在真实的 Claude Code 会话里实机跑过,装完请务必用上面那条命令验一次。
脚本的边界:
- 它读的是账号邮箱,不管 git 提交里的邮箱,那个建议改用 GitHub 提供的 noreply 地址。
- 邮箱被拆开拼接、或写进脚本文件再执行,它看不见。
- 我没把 PowerShell 工具写进 matcher,Windows 原生用户请按官方文档自己适配。
- 它只是多一道门,不是沙箱。
也可以在 CLAUDE.md 里加一条短规则,但只算加分项,别当防线:
– 我的账号邮箱不得出现在任何 User-Agent、请求头、网址或请求体里。
– 站点要求提供联系方式时,先停下来问我,我不同意就不要发这个请求。
六、顺手再查一个默认开着的设置:额度重置后自动续跑
写这篇时我顺手翻了官方文档,发现另一个“默认开启、会替你花额度”的设置,和上面的 2.1.234 是同一条更新:

- 终端/桌面里的 Claude Code:2.1.234 起,用 Claude 官方订阅账号登录的交互会话,碰到用量限制会在会话里等着,重置后自己接着干活。官方写明默认开启;关闭方式是 /config 里关掉 “Continue automatically at usage limit”,或在用户设置里把 autoContinueAtUsageLimit 设为 false。文档还写到,连续自动续跑 3 次后会停下。
- Claude Code Projects:Project settings 的 General 里有 “Auto-continue when usage limits reset”,文档同样写明默认开启,对整个项目生效,不只是当前线程。文档直说:续跑后的工作会计入你下一个用量窗口。
这两条我都对到了官方文档原文。说明一点:终端版“续跑会花下一个窗口的额度”是我的推断(文档只说会接着干活,干活就要用量),Projects 版文档里写得很明确。
关不关看你:习惯睡前丢长任务,自动续跑反而是便利;额度本来就紧,又不想一觉醒来下一个 5 小时窗口已被花掉,就关了。关掉后想继续,重置后发条消息即可。终端版在 settings.json 里关掉只要一行:
{
"autoContinueAtUsageLimit": false
}
我的看法
我最在意的不是“泄露多严重”,而是处理方式:团队承认了问题和“应该更早发现”,补丁公开源码、写明了边界,这些值得肯定;但一条“告诉模型别这么干”的文字规则 8 月就上线了,3 个月后还是漏了——不希望发生的事,只靠提示词不够,需要一道不经过模型的检查。
另一个体会:默认值就是产品替你做的决定。账号邮箱默认进上下文、额度重置默认自动续跑,各有各的理由,但都是“默认替你做主”。每次更新后花 3 分钟看看新增了哪些默认开启的东西,比事后复盘划算。
来源(纯文本,无链接)
- GitHub:anthropics/claude-code 的 issue #107757 及团队成员回复
- Hacker News:同一话题讨论帖及团队成员的说明
- Claude Code 官方文档:更新日志(2.1.317、2.1.318、2.1.234)、Interactive mode、Hooks guide、Claude Code Projects、会话转录存放位置
- anthropics/claude-code 仓库 mods/privacy 目录的 README(cc-plugin-privacy 的拦截与放行范围)
- 媒体整理:theterminal.space、madrobot.blog
- 命令与脚本:我在模拟数据上的测试,未在真实 Claude Code 会话中实机验证
如果你跑了上面第 3 步那条命令:命中了几条,是哪类站点(Wikipedia、SEC,还是别的 API)?在评论区报个数就行,别贴邮箱本身。我想看看这事在真实日志里到底有多普遍。



