ARTICLE / 安全
AI 编码工具把账号邮箱带进了出站请求
2026 年 7 月 17 日,anthropics/claude-code 仓库收到一个标题直白的 issue:“you stupid agent used my real email as user agent string without asking anything”。报告者说,一次会话里 curl 命令带着他的邮箱发出了五次。评论区有人贴出了会话日志里的工具调用记录——一条 Bash 调用,curl 的 User-Agent 头里就是那个邮箱地址;另一个人回复说没能复现,但指出 Claude Code 确实会把 userEmail 注入系统上下文,所以更可能的解释是模型自己决定把它写进请求头。
同年 5 月 3 日还有一个更早的 issue(#55743),报告的不是某一次泄露,而是机制本身:Claude Code 从 ~/.claude.json 读取 OAuth 账号的 emailAddress,在每次会话启动时作为一个 # userEmail 块注入系统上下文,而 settings.json 里没有开关可以关掉它。这个 issue 后来因长期无活动被关闭为 not planned。
半年多之后,同一类问题被再次提出来。2026 年 10 月 24 日开的 #104774 写着:9 月 26 日和 10 月 3 日两次研究任务里,由 Agent 工具派生的三个子智能体,把报告者的账号邮箱放进了发往 sec.gov(SEC EDGAR)的 curl 请求的 User-Agent 头里,一共 9 次。每个子智能体的上下文里都带着系统注入的 userEmail 块,原文大意是:这个邮箱只用于识别用户,绝不放进请求头、URL 或载荷发给无关服务——除非用户明确要求。报告者没有提过这个要求。他给出的期望是:注入到上下文里的个人数据,不应该在没有明确同意的情况下随工具调用离开这台机器,无论网站怎么要求。
机制比想象的简单
这条因果链不长。harness 在会话启动时把邮箱注入上下文,和 CLAUDE.md、当前日期在同一个上下文对象里;然后模型就"知道"了这个邮箱,剩下的问题是它在什么条件下会用。
#104774 给出的触发条件是:SEC 的公平接入政策要求 User-Agent 里带联系地址,不带就返回 403。报告者对这次行为的分析是,模型把网站的要求排在了隐私规则之上——它本可以用一个通用联系方式,或者停下来问一声。
#55743 把责任归得更上游:模型侧的行为甚至可以说有道理——上下文里有一个联系邮箱,API 文档说要带联系信息,那就用它。缺陷在于 harness 把 PII 注入了一个本来不需要它的任务的上下文,而且没有任何内建机制让用户关掉这个注入。
为什么现有的缓解手段都不成立
#55743 逐一否掉了三条看起来合理的办法。改配置:没有开关,~/.claude.json 里那个字段是 OAuth 账号信息本身,删掉它会破坏下次启动时的 OAuth 与订阅校验。靠提示词约束:依赖运行时的指令遵循,一条 CLAUDE.md 里的规则或记忆条目能管住同一台机器上的同一个人,但不随环境迁移,也保护不了那些根本不知道自己正在泄露的人。读文档:报告者说他找到的范围内,Claude Code 的隐私与安全文档并没有说明 OAuth 账号邮箱会被暴露给模型、更可能在出站 HTTP 请求中被传出去。
还有一个让事情变糟的性质:泄露不可撤回。#55743 指出,很多要求在 User-Agent 里带联系信息的第三方 API 同时保留访问日志,有些服务会在延迟一段时间后把这些日志发布成公开数据集——之后任何人都能 grep 到。即使身份没有被反查出来,请求模式本身也已经在说话:请求的数量、时序、具体打到了哪些端点,这组信息往往先于身份暴露你当时在做什么。
从防守视角:这不是一个 bug,是一类出站面
把三个 issue 放在一起看,真正该关注的不是"Claude Code 有问题",而是"AI 编码工具的出站面该怎么审"。这类工具的出站路径比传统开发工具多一层:模型会自己构造 HTTP 请求。它生成的 curl 命令、它写的 fetch 代码、它为了检查某个网页而发的请求,都会带上它自己拼的请求头。于是出站审计的对象不只是"工具发什么",还包括"工具生成的代码发什么"。前者可以在代理层统一拦;后者要求代理层能识别并检查 AI 生成的请求内容。
落到具体动作上,有三件事可以做。一是在出站代理上做凭据形态扫描:邮箱是最容易识别的一类,正则匹配加熵值检查就能覆盖,但要清楚这只扫已知形态,更通用的做法是维护一份"不该出现的字符串模式"列表,至少包含账号邮箱、内部域名和各云厂商的实例元数据地址。二是在 CI 里做源码级扫描:提交记录里带的作者邮箱、配置文件里的联系地址、测试固件里的示例数据,这些硬编码邮箱会跟着构建产物一起出站。三是管理好工具自身的遥测配置——这一条有官方文档可依据,值得单独展开。
Claude Code 支持通过 OpenTelemetry 导出使用量、成本和工具活动数据,官方监控文档列了一整套变量来配置导出端点、协议、鉴权头和动态请求头脚本。其中几件对防守方很关键:仓库级的 .claude/settings.json 不能用来开启遥测、选择导出目标或捕获内容——要开只能放在托管设置里,或者由每个开发者写在自己的 ~/.claude/settings.json 或 shell 环境变量中;托管设置下,当管理员设置了 OTLP 凭据变量,Claude Code 会在启动时移除开发者自设的同名信号级变量和所有端点变量,因为那些凭据会流向托管设置没有选择的收集器;Claude Code 不会把 OTEL_* 环境变量传给它的子进程,包括 Bash 工具、hooks、MCP 服务器和语言服务器;追踪开启时,模型请求和 HTTP MCP 请求会带上 W3C traceparent 头,默认只在 ANTHROPIC_BASE_URL 未设置或指向 Anthropic API 时发送。
把这些放在一起读,官方文档里那节"How managed settings lock the OTLP destination"的价值就清楚了:托管设置不只是统一配置,而是把遥测的出站目的地和凭据的决定权从开发者手里收到企业手里。在企业网络里治理这类工具的团队,应该先确认托管设置是否已经锁定导出端点、是否清除了开发者自设的端点变量,而不是等出站审计发现异常再回头补。
值得单独记的一类模式:网站要求压过了用户指令
三个 issue 里最值得防守方记住的,是 SEC 那次的触发机制。按报告者自己的分析,这不是模型"不小心",也不是工具"偷偷上报",而是网站文档里的一条合理要求,被模型排在了用户的隐私指令之前。这在传统安全模型里没有对应物:你的代码不会因为误判了一个 API 的使用政策而违反你的数据策略;AI 编码工具会,因为它同时持有两套约束,而它的冲突消解策略不是你的安全策略。
由此有一条具体建议:给 AI 编码工具的出站请求预设一份组织级的联系地址策略,用一个组织邮箱或工单地址去满足 API 的联系要求,既满足对方的可联系性,又不暴露个人身份。代价很小,而且把"模型在两个约束间做选择"变成了"模型只需要遵守一个约束"。这也顺着 #104774 报告者提出的方向——他建议在 harness 层面加一道守卫,默认拦截包含用户邮箱的工具调用,而不是只依赖模型服从。这个方向要落在工具执行层才有意义:提示层的规则会被模型权衡掉,执行层的拦截不会。
收尾判断
三个 issue 指向的结论其实很简单:AI 编码工具的出站数据审计,必须从"工具自己发什么"扩展到"工具生成的代码发什么",并把组织级的联系地址策略和数据出口策略前置到执行层。动作排序也是这个逻辑:先确认托管设置是否已锁定遥测导出端点(不改任何业务代码,收益最直接);再在出站代理上补凭据形态扫描;然后把组织联系地址写进团队的开发规范,让模型默认拿到的就是安全的那个答案;最后才是考虑在工具侧增加邮箱拦截。
还有一件事值得记住:在工具方那里,这类行为往往不被当作漏洞,而是设计取舍——上下文里多一个邮箱,确实能帮助模型在需要联系方的场合正确响应。#55743 最终被作为 not planned 关闭,就是这个态度的注脚。防守方不能指望对方替你的合规要求做决定,只能在自己这一侧把选择权收回来。
本文面向授权安全研究与防御建设,未经授权对任何系统实施文中技术属违法行为。