返回博客

Claude Code · 遥测检查

Claude Code 会把什么发出去?

我检查 Claude Code 有没有读取 MAC 地址和机器序列号时,也翻了本机的遥测目录。里面有 8 个发送失败的事件文件,共 173 条记录。

这次拆的是 macOS arm64 版 2.1.280,磁盘上的记录则来自 2.1.197 到 2.1.220。我用它们对照字段和生成代码,没有把旧日志当作新版本的运行结果。安装包哈希和复核方法放在文末。

设备 ID 从哪来

~/.claude/telemetry/ 中的这 173 条记录用了同一个设备 ID。其中 53 条带有账户和组织 UUID,37 条带有 Git HEAD SHA,也就是 Git 当前提交的标识。除了能把记录归到同一份安装下,部分记录还可以对应到账户和代码提交。

记录里还有一个叫 additional_metadata 的附加字段。它是 Base64 编码的 JSON,解码后能看到提示词长度、耗时、hook 名、模型提供商和操作分类。Base64 不提供加密保护,这些字段在本地就能读出来。

设备 ID 来自 ~/.claude.json 中的 userID。生成它的代码使用密码学随机数,没有拿 MAC 或序列号作输入。这个值保存到本地后会被反复使用,在 Anthropic 事件里叫 device_id。因此,即使没有硬件编号,同一份安装产生的多条记录仍能按这个值关联。

配置里另一个字段 machineID 也来自随机字节。Datadog 错误报告会取它的前 12 个字符。模型请求也有自己的标识字段:metadata.user_id 中包含设备和会话标识。

01 userID 保存在本地,发送事件时复用
生成随机 ID这条生成路径未使用硬件信息
保存到配置文件~/.claude.json 中的 userID
写入事件记录device_id、session_id
登录后部分记录还带账户 UUID
图中只列字段名,没有展示本机的实际 ID。

这些文件属于发送失败队列。我没有对应时段的网络记录,不知道哪些后来重试成功,也不知道服务端收到了多少。

改了 API 地址,还会往哪里发

模型请求会携带你的问题、放进上下文的代码,以及工具执行结果,发到当前使用的模型服务端。关闭遥测后,完成任务所需的这些请求仍会发送。

在 2.1.280 的代码里,我还找到了 Anthropic 事件批次接口和 Datadog 日志的发送路径。前者接收使用事件,后者接收一部分事件的副本及错误报告。能否发出,还要经过提供商、凭据、禁用设置和采样等条件的检查。官方网络文档列出的两个 Datadog 接收地址,也分别对应运行事件和错误报告。

OpenTelemetry 用来把监控日志和指标导出到配置的接收地址。这个地址可以由用户设置,也可以由组织的托管配置下发。它和 Anthropic 自己的运行遥测分开,配置方法见官方监控文档。

02 模型请求、使用事件和监控日志的发送路径
Claude Code 2.1.280 代码中查到的发送路径
模型调用当前模型服务端

接收提示词、上下文、工具结果和会话标识等。

随模型请求发送
使用事件Anthropic 批次接口

核心代码和内置 telemetry 插件构造的事件,可发往 api.anthropic.com。

受提供商、凭据、开关、采样等条件限制
日志与错误Datadog

选定事件的副本和错误报告,分别使用两个日志接收地址。

各有发送条件和字段清洗
自建监控OpenTelemetry

通过导出器,把日志和环境属性发到配置的 OTLP 接收端。

需要启用导出器并配置接收端
这是按代码整理的路径图,没有对应会话的抓包。WebFetch 域名预检等按功能触发的请求未全部画入。

我还查了自定义模型地址 ANTHROPIC_BASE_URL。已追到的核心遥测代码没有直接把这个变量作为禁用条件,所以单凭改了模型地址,还不能判断其他上报是否停止。自定义地址如何影响凭据,以及这些影响会不会继续阻止发送,这次没有全部追完。

日志里会不会有提示词和代码

我按 JavaScript 中直接写出的事件名统计了调用点:2,603 处调用,1,713 种事件名,分布在 261 个模块里。它们覆盖的是程序可能记录的操作,不是一次会话实际发送的条数。动态拼出的事件名没有计入;通过展开运算符合并进去的字段,也需要回头查它们的来源。

内置 telemetry 插件不接受任意文本字符串,只收布尔值、有限数值和预先列好的选项。核心事件则在各个调用位置处理参数。普通模式下,没有统一的字段白名单覆盖所有事件。

例如,查过的 Bash 事件会先解析命令,再记录命令类别、白名单中的程序名和结构特征;API 错误事件记录限定的错误类型、状态和重试次数;一些工具异常会把错误消息处理成哈希和堆栈特征。几个名叫 paths 的字段里,实际装的是计数或枚举值,没有路径原文。

03 两套事件接口,字段限制不同
核心事件各处 tengu_* 调用分别处理事件参数附加数据编码为 Base64 JSON普通模式下没有覆盖所有事件的统一字段白名单
内置 telemetry 插件$.telemetry.log / mark拒绝任意文本字符串接收布尔值、有限数值、预设选项只有内置和核心来源能调用该接口
Anthropic 事件批次接口 /api/event_logging/v2/batch

我也按绝对路径、邮箱和令牌的常见格式扫描了那 173 条旧记录,没有命中。在查过的默认遥测代码中,没有发现发送完整提示词、源文件正文或原始 Bash 命令的路径。不过,上千种事件的字段还没有全部查完,这个结果不能推广到整套程序。

Datadog 的两类上报也会处理字段。事件副本先删去一组敏感字段,再统一工具名、模型名和 HTTP 状态的格式;错误报告会清洗异常消息和堆栈,并限制单个进程中排队的报告数量。清洗规则可能漏掉用户自定义的秘密值。包里还能搜到 sentry.io,但沿着 logError 查到实际的 POST 后,这条 CLI 错误上报用的是 Datadog。

OpenTelemetry 可以通过配置记录提示词原文。OTEL_LOG_USER_PROMPTS 默认关闭;开启它,并启用相应的日志导出后,提示词内容就能进入配置的监控接收端。

官方文档还列出默认关闭的 OTEL_LOG_RAW_API_BODIES,可以记录包含对话历史的模型 API 请求和响应 JSON。设为 1 时,正文写进日志事件,超过内容长度限制会被截断;文件模式把未截断内容写到本地,事件里放文件引用。文件保存在本地,不代表文件正文已随事件上传。这部分是文档中的配置说明,没有在本机补做导出测试。

MAC、序列号和时区

在提取出的 JavaScript 中,我没有找到常见的 MAC 地址和机身序列号读取调用。不过,随包的 OpenTelemetry 组件里有一处 ioreg 调用,会读取 IOPlatformUUID。这项结果能否导出,还取决于相应的环境信息检测和 OTLP 导出是否启用;本次检查的普通本机会话中,没有看到已配置的 OTLP 接收地址。

hostname,也就是主机名,用在监控环境信息、远程控制的设备名和本地同意记录等地方。本机 IP 还要区分读取网卡地址与网络连接本身:已检查的 JS 没有主动读取网卡 IP 的应用调用,接收请求的服务器仍然能看到连接的来源 IP。

包内还有截屏、输入和录音相关的三个原生扩展。我没有发现它们在后台自动录制并通过默认遥测上传的证据,但也没有完成这些扩展的反编译审计。

04 硬件与环境信息的检查结果
信息查到的代码发送条件或检查范围
IOPlatformUUIDOpenTelemetry 的 getMachineId 调用 ioreg需要相应的环境信息检测和 OTLP 导出生效
hostnameOTel hostDetector、远程控制设备名、本地同意记录几处用途不同,不能合并判断是否发送
MAC / 机身序列号在提取的 JS 中未找到常见读取调用未完整审计原生扩展和 Bun 运行时
本机 IP已查的 JS 未主动读取网卡 IP接收端仍可看到连接的来源 IP
屏幕 / 音频包内有截屏、输入、录音相关原生扩展未发现后台自动录制并经默认遥测上传的证据;扩展未完整审计

时区还有一条旧版本的线索。2026 年 6 月,一位用户在 Claude Code 仓库提交的报告展示了日期行的变化:自定义 API 主机名不同,系统提示词会换用外观接近的撇号;某些时区还会改变日期分隔符。变化直接出现在发给模型的文字里,没有使用单独的遥测字段。报告描述了现象,不能据此确认这些字符变化的用途。

我对照检查了 2.1.280 的日期行构造。它用普通 ASCII 撇号和 YYYY-MM-DD 格式,没有找到旧报告里的字符选择逻辑。这个结果只针对本次的 macOS 安装包。

05 旧版报告与本次检查的日期行
旧版本的用户报告API 主机名、系统时区改变撇号字符和日期分隔符
'’ʼʹYYYY/MM/DD
变化写进系统提示词的日期行
本次检查的 2.1.280检查提取出的 JS 模块日期行使用固定格式
Today's date isYYYY-MM-DD
未找到旧版按时区和主机名选择字符的逻辑

哪些开关能关闭上报

按 2026 年 9 月 24 日核对的官方数据使用文档,可以用下面的命令启动 Claude Code,关闭非必要流量:

CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 claude

单独关闭使用指标用 DISABLE_TELEMETRY=1,关闭错误报告用 DISABLE_ERROR_REPORTING=1。前者和关闭非必要流量的总开关,还会停用 Remote Control 依赖的功能标志检查;只关错误报告不会。

这些功能标志由服务端下发,客户端据此启用或关闭部分功能。检查当天,我的本机缓存里有 700 个 GrowthBook 标志。其中一条远程控制路径会在相应标志关闭后停止服务。

06 远程功能配置与本地发送开关
刷新远程配置GrowthBook 功能标志
客户端检查开关tengu_ccr_bridge
关闭时停止服务停止远程控制的 bridge
遥测发送代码另行检查本地环境变量
本地环境变量DISABLE_TELEMETRY 等
是否允许发送事件由各条发送路径检查

700 个是当天的缓存数量,我没有逐项审完。这条远程控制代码能说明服务端配置会影响功能,但不能证明远端可以绕过本地遥测禁用设置。

关掉非必要流量以后,WebFetch 的域名安全预检仍会运行。它有独立的设置 skipWebFetchPreflight;设为 true 会跳过检查,也会放弃这层域名安全保护。官方插件市场的自动安装也不受上述总开关控制,要单独用 CLAUDE_CODE_DISABLE_OFFICIAL_MARKETPLACE_AUTOINSTALL=1 关闭。这些例外在同一份官方文档中列出。

在公司环境里,还要看组织下发的 OpenTelemetry 配置。即使自己的终端没有设置接收地址,托管配置也可能提供它。需要限制出站连接时,可以按官方网络文档核对目的地,在网关或防火墙上设置规则,再检查实际请求是否符合预期。

公开排查结果前,先删去凭据和标识符。不要把完整的 ~/.claude.json、遥测队列或抓包文件贴到网上。

安装包信息与复核方法

检查对象为 macOS arm64 版 Claude Code 2.1.280,安装文件 SHA-256 是 387a5c5dcdbb815085edf0baf79591f9d8894efe922bceaf3d75b1b08055229d。本机观察发生在 2026 年 9 月。

我先在二进制里搜索 IOPlatformUUID、networkInterfaces 和时区字符串,再解析 Bun 单文件程序的模块图,提取 JS。字符串搜索用来找入口;后面的检查沿着事件生成、字段处理和发送函数继续看,避免把字符串出现的位置误当作实际调用。

07 安装包和旧日志分别检查了什么
核对安装包Mach-O · 217 MB
版本、签名、SHA-256
提取 Bun 模块2,213 条记录
1,991 个 JS 模块
追踪事件到发送函数字段、清洗、发送条件
序列化、POST

模块图包含 37,884,508 字节可读的 JS 源文本和 82,505,096 字节字节码。提取出的 1,991 个 JavaScript 模块全部通过语法解析。文件多叫 chunk-xxxxxxxx.js,函数名经过压缩,也没有随包源码映射;事件名、上报地址和字段名仍能读到。Bun 文档说明,启用字节码编译并不会隐藏源代码。

复核时先用下面的命令确认版本文件、哈希、签名和 Bun 段,再按模块图提取 JS。固定偏移只适用于对应的安装包,换版本后不能直接沿用;按偏移硬截一段二进制,也可能混入非源码内容。

CC="$HOME/.local/share/claude/versions/2.1.280"
shasum -a 256 "$CC"
codesign -dv --verbose=2 "$CC"
otool -l "$CC" | rg -A8 'sectname __bun|segname __BUN'

这份包中,chunk-m200zvyg.js 包含核心事件的序列化和 Datadog 事件副本处理,chunk-h8651pre.js 包含内置 telemetry 插件,chunk-s8swgzep.js 包含错误上报的条件检查。模块名会随版本变化。

没有搜到字符串,也可能是实现换了写法或编译到了其他位置。本次没有逐指令审计 Bun 运行时和三个原生扩展,没有对应会话的 TLS 明文抓包,也没有服务端保存记录。

文章目录5
Silent Star约 10 分钟