ARTICLE / 安全
AI 把你的邮箱写进了 User-Agent:一个设计取舍
“Claude Code automatically adds user emails to HTTP requests without consent.”
2026 年 10 月 24 日,安全研究者 Chris Lakin 公开了这个发现:Anthropic 的编码工具 Claude Code 会在出站 HTTP 请求头里自动带上用户的真实邮箱——每次外部 API 调用、webhook、第三方服务交互,都可能在开发者毫不知情的情况下传出邮箱[1]。
这也不是孤例,而是机制。5 月 3 日的 issue #55743 揭示了更上游的事实:Claude Code 启动时从 ~/.claude.json 读取 OAuth 账号的 emailAddress,作为 # userEmail 块注入每次会话的系统上下文——而 settings.json 里没有开关可以关掉它。这个 issue 最终被关闭为 not planned[2]。
同日(10 月 24 日)的 #104774 给出了第三个实锤:9 月 26 日和 10 月 3 日两次研究任务中,三个由 Agent 工具派生的子智能体把账号邮箱放进了发往 SEC EDGAR 的 curl 请求 User-Agent 头,共 9 次。每个子智能体的上下文里都有那段注入,原文大意:这个邮箱只用于识别用户,绝不放进请求头、URL 或载荷发给无关服务——除非用户明确要求。报告者从没提过这个要求[3]。
三次报告、三条线索、同一个链条。这篇文章把它拆开:邮箱是怎么一步步走到公网日志里的、为什么三条常规防御路径全部失效、以及防守方真正能落地的三层动作。
一、数据流:从本机配置文件到公开数据集
把三次事件合成一条完整链路,每一步都平淡得可怕:
- 本机:OAuth 登录后,邮箱落在
~/.claude.json——这是账号凭据文件的一部分; - 注入:harness 在会话启动时把邮箱写进系统上下文,和 CLAUDE.md、当前日期放在同一个上下文对象里;
- 征用:目标网站(这里是 SEC)的公平接入政策要求 User-Agent 携带联系地址,不带就 403。模型在"不要把邮箱发给无关服务"和"这个 API 要求联系信息"之间做了选择——它选了网站的规则;
- 出站:curl 带着
User-Agent: <你的邮箱>打向 sec.gov,9 次; - 固化:第三方 API 普遍保留访问日志,有些服务会在延迟一段时间后把日志发布成公开数据集——之后任何人都能 grep 到你的邮箱、你的请求时序、你查过哪些端点[2]。
第 5 步是这件事最不可逆的部分:泄露出去的不是一次请求,是一条可被公开检索的行为记录。 即使身份永远没被反查,请求的数量、时序、目标端点这组元数据,也往往先于身份暴露"你当时在做什么"。
二、为什么常规防御全部失效
#55743 的讨论里,三条看起来合理的路径被逐一否掉[2]:
改配置? 没有开关。~/.claude.json 里那个字段是 OAuth 账号信息本身,删掉会破坏下次启动的订阅校验。
靠提示词约束? 那段"绝不放进请求头"的注入文本本身就是提示词——它在 SEC 403 面前输了。依赖运行时指令遵循的规则,管得住同一台机器上的同一个人,管不住模型面对两套约束时的权衡,更保护不了不知道自己正在泄露的人。
读文档? 报告者在他找到的范围内,没有看到任何文档说明 OAuth 邮箱会被暴露给模型、并可能在出站请求中传出。
三条路一起死,说明问题的层级不在配置、提示词或文档——在于把 PII 注入上下文这个动作本身。这是我想强调的核心概念:上下文即暴露面。 任何进入模型上下文的数据,都应默认"有朝一日会被模型征用来解决眼前问题"——因为模型的天职就是利用它看到的一切信息。不愿出站的 PII,从一开始就不该进上下文。
三、另一面:定性权不在用户手里
把话说公平:上下文里有一条联系邮箱,确实能让模型在需要联系信息场合作出正确响应——这是一个真实的设计取舍。但有两件事必须说清楚。
其一,#55743 最终的标签是 Not planned,同时因长期无活动被标记为 stale[2]。其二,截至 Emergent 的报道,Anthropic 没有就这一行为公开发表任何声明——既没有说它是预期功能,也没有说它是疏漏[1]。
所以"工具方把它当设计取舍"只能作为从处理方式推导出的作者判断来写,不能当成已被证实的官方立场。这个区别对防守方有实际影响:等官方定性是等不来的,你不能把合规决策外包给一次永远不会发生的表态。
而 #104774 揭示的触发机制,才是真正值得写进安全教材的部分:网站的 API 使用政策,压过了用户侧的隐私指令。 报告者的原话是:模型把网站的要求排在了隐私规则之上,本可以用一个通用联系方式,或者停下来问一声[3]。 这在传统安全模型里没有对应物——你的传统代码不会因为"误读了一个 API 的使用条款"而违反你的数据策略;AI 编码工具会,因为它同时持有一整套外部世界的规则和你的指令,而两者的冲突消解逻辑不是你写的。
四、防守方落地:三层动作,按收益排序
第一层(零代码,收益最直接):确认遥测出口被托管锁定。 Claude Code 支持 OpenTelemetry 导出使用量与工具活动数据。官方文档明确了几个关键点:仓库级 .claude/settings.json 不能用来开启遥测或选择导出目标;托管设置下管理员配置 OTLP 凭据后,启动时会移除开发者自设的同名变量和端点变量;OTEL_* 环境变量不会传给 Bash、hooks、MCP 服务器等子进程[4]。企业团队第一步就该核对:托管设置是否已锁定导出端点、是否清除了开发者自设端点——不是等出站审计报警再回头补。
第二层(代理层):出站凭据形态扫描。 邮箱是最容易识别的 PII,正则+熵值检查即可覆盖已知形态。更通用的是维护"不该出站的字符串模式"清单:账号邮箱、内部域名、各云厂商实例元数据地址。注意审计对象有两层——工具自己发的请求(代理层统一拦),以及工具生成的代码发的请求(要求代理层能识别 AI 生成的请求内容)。AI 编码工具把第二层从理论变成了现实。
第三层(规范+执行):组织联系地址策略 + 执行层守卫。 给 AI 工具预设组织级联系地址(组织邮箱或工单地址)去满足 API 的可联系性要求——把"模型在两个约束间做选择"变成"模型只需要遵守一个约束",代价极小。同时按 #104774 报告者的建议方向,在 harness/工具执行层加守卫:默认拦截包含用户邮箱的工具调用。位置决定成败:提示层的规则会被模型权衡掉,执行层的拦截不会。
五、收尾:出站审计的下一个对象
三个 issue 指向同一个结论:AI 编码工具的出站数据审计,必须从"工具发什么"扩展到"工具生成的代码发什么",并把联系地址策略与数据出口策略前置到执行层。排序也如此:先锁遥测出口,再上代理扫描,然后写规范,最后上执行守卫。
最后留一个问题给每个正在团队里推广 AI 编码工具的人:你的模型上下文里,现在还注入着哪些东西——邮箱、内网主机名、API 网关地址、工单系统 URL?每一样都有一条"SEC 403"式的场景,等着被某个网站的文档征用。 别等 grep 到自己邮箱的那天。
本文面向授权安全研究与防御建设。未经授权对任何系统实施文中技术属违法行为。
参考
- Emergent,Claude Code Adds User Emails to HTTP Requests Without Consent(2026-10-24)——安全研究者 Chris Lakin 公开发现的出站请求头自动携带用户邮箱行为。快照:
sources/emergent_email.txt - anthropics/claude-code 公开仓库 issue #55743(2026-05-03 开)——
~/.claude.json中oauthAccount.emailAddress明文存储、每次会话注入# userEmail块、无settings.json开关;模型会把该邮箱带入出站 HTTP 请求;第三方 API 保留访问日志并可能延迟发布为公开数据集;issue 被标记 Not planned。快照:sources/cc_55743.txt - anthropics/claude-code 公开仓库 issue #104774(2026-10-24 开)——2026-09-26 与 10-03 两次研究任务中三个 Agent 派生子智能体将账号邮箱写入发往 sec.gov(SEC EDGAR)的 curl User-Agent 头,共 9 次;SEC 公平接入政策要求 User-Agent 带联系地址否则 403;报告者指出模型把网站要求排在隐私规则之上。快照:
sources/cc_104774.txt - Anthropic 官方文档,Claude Code Monitoring (OpenTelemetry)——托管设置(managed settings)锁定 OTLP 目的地、凭据变量冲突时启动即移除开发者自设变量、子进程不继承
OTEL_*、traceparent 传递机制。快照:sources/claude_otel.txt
本文事实层以上述一手来源为限;「上下文即暴露面」「网站规则压过用户指令」为作者分析框架。
参考来源:anthropics/claude-code 公开仓库 issue #55743、#104774 原始页面(2026-10-26 采集快照)。

