Checkpoint the full local bridge and audit work before telemetry removal

You asked for all local code to be committed before the broader telemetry-removal pass. This commit snapshots the current bridge/session ingress changes together with the local audit documents so the next cleanup can proceed from a stable rollback point.

Constraint: Preserve the exact local worktree state before the telemetry-removal refactor begins
Constraint: Avoid mixing this baseline snapshot with the upcoming telemetry deletions
Rejected: Fold these staged changes into the telemetry-removal commit | Would blur the before/after boundary and make rollback harder
Confidence: medium
Scope-risk: moderate
Reversibility: clean
Directive: Treat this commit as the pre-removal checkpoint when reviewing later telemetry cleanup diffs
Tested: Not run (baseline snapshot commit requested before the next cleanup pass)
Not-tested: Runtime, build, and typecheck for the staged bridge/session changes
This commit is contained in:
2026-04-09 14:09:44 +08:00
parent 523b8c0a4a
commit 5af8acb2bb
8 changed files with 1382 additions and 91 deletions

View File

@@ -0,0 +1,430 @@
# 本地系统信息外发审计报告
- 审计时间: 2026-04-03
- 审计对象: `/Users/yovinchen/project/claude`
- 审计方式: 静态代码扫描 + 关键数据流人工追踪
- 说明: 本报告基于源码静态分析得出,未做运行时抓包或服务端行为验证。
## 结论摘要
结论是: **存在“采集本地/环境信息并向外发送”的代码路径,而且其中一部分是默认链路。**
我把风险按类型拆开后,结论如下:
1. **默认会发生的外发**
- 模型请求链路会把本地环境信息放进 system prompt / meta message 后发送给 Claude API。
- analytics/telemetry 链路会把平台、架构、Node 版本、终端、运行时、Linux 发行版、进程内存/CPU 指标等发送到 Datadog 和 Anthropic 1P 事件日志接口。
2. **用户显式触发后才会发生的外发**
- Feedback / Transcript Share 会上传 transcript、平台信息、错误信息、最近 API 请求等。
- Remote Control / Bridge 会上传 `hostname`、本地目录、git 分支、git remote URL。
- Trusted Device 注册会上传 `hostname + platform` 组成的设备显示名。
- 可选 OpenTelemetry 在启用后会把 `user.id``session.id``organization.id``user.email``terminal.type` 等发往配置的 OTLP endpoint。
3. **目前未发现的自动采集项**
- 未发现自动读取并外发 MAC 地址、网卡列表、IP 地址、`/etc/machine-id`、BIOS/主板序列号、硬件 UUID、`dmidecode``ioreg``system_profiler` 之类更敏感的硬件唯一标识。
4. **额外重要发现**
- 这套代码不仅会外发“系统信息”,还会外发一部分“项目上下文”。
- 典型例子包括: 当前工作目录、是否 git 仓库、当前分支、main 分支、git user.name、`git status --short`、最近 5 条提交、`CLAUDE.md` 内容、当前日期。
## 审计方法
本次审计主要做了两件事:
1. 搜索本地系统/环境信息采集点。
- 关键词包括 `os.*``process.platform``process.arch``process.env``hostname()``userInfo()``/etc/os-release``uname``git status``getCwd()` 等。
2. 搜索外发点并做数据流关联。
- 关键词包括 `axios.post``fetch``WebSocket``anthropic.beta.messages.create``Datadog``event_logging``trusted_devices``/v1/environments/bridge``/v1/sessions` 等。
## 发现清单
| 编号 | 链路 | 是否默认 | 外发内容 | 目标位置 | 结论 |
| --- | --- | --- | --- | --- | --- |
| F1 | 模型请求 system prompt / user context | 是 | cwd、平台、shell、OS 版本、git 状态、git 用户、最近提交、`CLAUDE.md`、日期 | Claude API | 已确认 |
| F2 | Datadog analytics | 是 | 平台、架构、Node 版本、终端、运行时、Linux 发行版/内核、进程 CPU/内存、repo remote hash | Datadog | 已确认 |
| F3 | Anthropic 1P event logging | 是 | 与 F2 类似,外加 user/account/org 元数据与 process blob | `https://api.anthropic.com/api/event_logging/batch` | 已确认 |
| F4 | GrowthBook remote eval | 大概率是 | deviceId、sessionId、platform、org/account、email、版本、GitHub Actions 元数据 | `https://api.anthropic.com/` 上的 GrowthBook 接口 | **推断成立概率高** |
| F5 | Feedback | 否,用户触发 | platform、terminal、是否 git、transcript、raw transcript、errors、lastApiRequest | `https://api.anthropic.com/api/claude_cli_feedback` | 已确认 |
| F6 | Transcript Share | 否,用户触发 | platform、transcript、subagent transcripts、raw transcript JSONL | `https://api.anthropic.com/api/claude_code_shared_session_transcripts` | 已确认 |
| F7 | Remote Control / Bridge | 否,功能触发 | hostname、directory、branch、git_repo_url、session context | `/v1/environments/bridge``/v1/sessions` | 已确认 |
| F8 | Trusted Device | 否,登录/设备注册 | `Claude Code on <hostname> · <platform>` | `/api/auth/trusted_devices` | 已确认 |
| F9 | OpenTelemetry | 否,需启用 | user/session/account/email/terminal + OTEL 检测到的 OS/host arch | 配置的 OTLP endpoint | 已确认 |
| F10 | `/insights` 内部上传 | 非外部版默认不可用 | username、报告文件 | S3 | 已确认,且 `ant-only` |
## 详细分析
### F1. 默认模型请求链路会外发本地环境和项目上下文
证据链如下:
1. `src/constants/prompts.ts:606-648``computeEnvInfo()` 会构造环境块,包含:
- `Working directory`
- `Is directory a git repo`
- `Platform`
- `Shell`
- `OS Version`
2. `src/constants/prompts.ts:651-709``computeSimpleEnvInfo()` 也会构造同类信息,且包含 `Primary working directory`
3. `src/context.ts:36-103``getGitStatus()` 会进一步读取:
- 当前分支
- main 分支
- `git config user.name`
- `git status --short`
- 最近 5 条提交
4. `src/context.ts:116-149``getSystemContext()` 会把 `gitStatus` 注入系统上下文。
5. `src/context.ts:155-187``getUserContext()` 会把 `CLAUDE.md` 内容和当前日期放入用户上下文。
6. `src/utils/api.ts:437-446``appendSystemContext()` 会把 `systemContext` 拼到 system prompt。
7. `src/utils/api.ts:449-470``prependUserContext()` 会把 `userContext` 作为 `<system-reminder>` 前置到消息里。
8. `src/query.ts:449-450``src/query.ts:659-661` 把这两部分上下文真正交给模型调用。
9. `src/services/api/claude.ts:3213-3236` 会把 `systemPrompt` 序列化为 API 文本块,`src/services/api/claude.ts:1822-1832` 通过 `anthropic.beta.messages.create(...)` 发出请求。
结论:
- **这是默认链路**,不是用户额外点击“上传”后才发生。
- 外发的不只是主机 OS 信息,还包括当前项目目录和 git 元信息。
- 从数据敏感性看,`cwd``git user.name`、最近提交标题、`CLAUDE.md` 都可能包含组织或项目标识。
### F2. 默认 Datadog analytics 会外发环境与进程指标
证据链如下:
1. `src/main.tsx:416-430` 会在启动早期初始化用户/上下文/analytics gate。
2. `src/main.tsx:943-946` 会初始化 sinks从而启用 analytics sink。
3. `src/services/analytics/metadata.ts:417-467` 定义了要采集的 `EnvContext``ProcessMetrics` 字段。
4. `src/services/analytics/metadata.ts:574-637` 实际构造环境信息,包含:
- `platform` / `platformRaw`
- `arch`
- `nodeVersion`
- `terminal`
- `packageManagers`
- `runtimes`
- `isCi`
- `isClaudeCodeRemote`
- `remoteEnvironmentType`
- `containerId`
- `github actions` 相关字段
- `wslVersion`
- `linuxDistroId`
- `linuxDistroVersion`
- `linuxKernel`
- `vcs`
5. `src/services/analytics/metadata.ts:648-678` 采集进程指标,包含:
- `uptime`
- `rss`
- `heapTotal`
- `heapUsed`
- `external`
- `arrayBuffers`
- `constrainedMemory`
- `cpuUsage`
- `cpuPercent`
6. `src/services/analytics/metadata.ts:701-739` 会把这些信息合并进每个 analytics event并附加 `rh`
7. `src/utils/git.ts:329-337` 表明 `rh`**git remote URL 的 SHA256 前 16 位哈希**,不是明文 remote URL。
8. `src/services/analytics/datadog.ts:12-13` 指向 Datadog endpoint`src/services/analytics/datadog.ts:108-115` 通过 `axios.post(...)` 发送。
结论:
- **Datadog 默认是活跃链路**,除非被隐私设置或 provider 条件关闭。
- 这条链路没有看到把 `cwd`、源码正文、文件路径直接送去 Datadog它主要发送环境维度与运行指标。
- repo remote 不是明文发出,而是哈希值。
### F3. 默认 Anthropic 1P event logging 也会外发环境与身份元数据
证据链如下:
1. `src/services/analytics/firstPartyEventLogger.ts:141-177` 表明 1P event logging 默认启用时,会把 `core_metadata``user_metadata``event_metadata` 一起记录。
2. `src/services/analytics/firstPartyEventLoggingExporter.ts:114-120` 指定 1P 上报 endpoint 为:
- `https://api.anthropic.com/api/event_logging/batch`
- 或 staging 对应路径
3. `src/services/analytics/firstPartyEventLoggingExporter.ts:587-609` 表明最终通过 `axios.post(this.endpoint, payload, ...)` 发送。
4. `src/services/analytics/metadata.ts:796-970` 表明在 1P 格式化阶段,以下字段会进入上报内容:
- `platform/platform_raw`
- `arch`
- `node_version`
- `terminal`
- `package_managers`
- `runtimes`
- `is_ci`
- `is_github_action`
- `linux_distro_id`
- `linux_distro_version`
- `linux_kernel`
- `vcs`
- `process` base64 blob
- `account_uuid`
- `organization_uuid`
- `session_id`
- `client_type`
结论:
- **这也是默认链路**。
- 与 Datadog 相比1P event logging 能接收更完整的内部结构化元数据。
### F4. GrowthBook 很可能会把本地/身份属性发到远端做特性分流
证据链如下:
1. `src/services/analytics/growthbook.ts:454-484` 构造了 `attributes`,包含:
- `id` / `deviceID`
- `sessionId`
- `platform`
- `apiBaseUrlHost`
- `organizationUUID`
- `accountUUID`
- `userType`
- `subscriptionType`
- `rateLimitTier`
- `firstTokenTime`
- `email`
- `appVersion`
- `githubActionsMetadata`
2. `src/services/analytics/growthbook.ts:526-536` 使用:
- `apiHost`
- `attributes`
- `remoteEval: true`
创建 `GrowthBook` client。
判断:
- 由于真正的 HTTP 逻辑在第三方库内部,不在本仓库源码里直接展开,所以这里我不能把“已确认发送”说死。
- 但从 `attributes + apiHost + remoteEval: true` 的组合看,**高概率**存在把这些属性发送到 GrowthBook 后端做远程特性评估的行为。
- 这一条应标记为 **推断**,但可信度较高。
### F5. Feedback 会在用户触发时上传平台、转录、错误和最近请求
证据链如下:
1. `src/components/Feedback.tsx:54-68``FeedbackData` 定义包含:
- `platform`
- `gitRepo`
- `version`
- `transcript`
- `rawTranscriptJsonl`
2. `src/components/Feedback.tsx:206-224` 实际组装 `reportData` 时还加入:
- `terminal`
- `errors`
- `lastApiRequest`
- `subagentTranscripts`
3. `src/components/Feedback.tsx:543-550` 发送到 `https://api.anthropic.com/api/claude_cli_feedback`
结论:
- 这是 **用户显式触发** 的上传,不属于静默默认遥测。
- 但数据面比普通 analytics 大得多,包含对话转录和最近 API 请求内容。
### F6. Transcript Share 会在用户触发时上传 transcript 和平台
证据链如下:
1. `src/components/FeedbackSurvey/submitTranscriptShare.ts:37-70` 采集:
- `platform`
- `transcript`
- `subagentTranscripts`
- `rawTranscriptJsonl`
2. `src/components/FeedbackSurvey/submitTranscriptShare.ts:87-94` 发送到 `https://api.anthropic.com/api/claude_code_shared_session_transcripts`
结论:
- 这是 **显式分享链路**
- 风险面和 Feedback 类似,重点在 transcript 内容,而不是系统信息本身。
### F7. Remote Control / Bridge 会上传 hostname、目录、分支、git remote URL
证据链如下:
1. `src/bridge/bridgeMain.ts:2340-2452``src/bridge/bridgeMain.ts:2874-2909` 都会在 bridge 启动时读取:
- `branch`
- `gitRepoUrl`
- `machineName = hostname()`
- `dir`
2. `src/bridge/initReplBridge.ts:463-505` 也会把 `hostname()`、branch、gitRepoUrl 传入 bridge core。
3. `src/bridge/bridgeApi.ts:142-183` 注册环境时 POST 到 `/v1/environments/bridge`,字段包括:
- `machine_name`
- `directory`
- `branch`
- `git_repo_url`
- `max_sessions`
- `worker_type`
4. `src/bridge/createSession.ts:77-136` 创建 session 时还会把 git 仓库上下文放进 `session_context`,包括:
- 规范化后的 repo URL
- revision / branch
- owner/repo
- model
结论:
- 这是 **功能型外发**,不是无条件默认发生。
- 但一旦启用 Remote Control它会把本地主机名和项目标识信息发送出去。
### F8. Trusted Device 会上传 hostname + platform
证据链如下:
1. `src/bridge/trustedDevice.ts:145-159` 会向 `${baseUrl}/api/auth/trusted_devices` 发送:
- `display_name: "Claude Code on <hostname> · <platform>"`
结论:
- 这是 **登录/设备注册链路**,不是普通对话请求。
- 这里出现了明确的 `hostname()` 外发。
### F9. OpenTelemetry 是可选链路,但一旦启用也会对外发送本地属性
证据链如下:
1. `src/utils/telemetry/instrumentation.ts:324-325` 表明只有 `CLAUDE_CODE_ENABLE_TELEMETRY=1` 时才启用。
2. `src/utils/telemetry/instrumentation.ts:458-510` 会组装 OTEL resource包含:
- service/version
- WSL version
- OS detector 结果
- host arch detector 结果
- env detector 结果
3. `src/utils/telemetry/instrumentation.ts:575-607` 会初始化 log exporter 并对外发送。
4. `src/utils/telemetryAttributes.ts:29-68` 还会加入:
- `user.id`
- `session.id`
- `app.version`
- `organization.id`
- `user.email`
- `user.account_uuid`
- `user.account_id`
- `terminal.type`
结论:
- 这是 **可选链路**,默认不是强制开启。
- 但如果启用并配置了 OTLP endpoint确实会把本地身份/终端/会话属性发到外部。
### F10. `/insights` 还存在内部版上传链路
证据链如下:
1. `src/commands/insights.ts:2721-2736` 报告元数据包含:
- `username`
- 生成时间
- 版本
- 远程 homespace 信息
2. `src/commands/insights.ts:3075-3098` 会在 `process.env.USER_TYPE === 'ant'` 时尝试上传 HTML 报告到 S3。
结论:
- 这是 **内部版 ant-only** 逻辑,不应算外部公开版本默认行为。
- 但从源码角度,确实存在上传用户名和报告的链路。
## 未发现项
本次静态审计中,**没有发现**以下类型的自动采集/外发实现:
- `os.networkInterfaces()`
- `os.userInfo()` 用于遥测/外发
- `/etc/machine-id`
- `node-machine-id`
- `dmidecode`
- `ioreg`
- `system_profiler`
- `wmic bios`
- `getmac`
- `ifconfig` / `ip addr` / `ipconfig /all` 被程序主动执行用于遥测
- MAC 地址、IP 地址、硬件序列号、主板 UUID、BIOS UUID 等硬件唯一标识
补充说明:
- 搜到的 `ip addr``ipconfig``hostname` 主要出现在 Bash/PowerShell 工具的只读命令校验规则里,不是程序自身自动采集再上报。
- `hostname()` 的真实外发点主要集中在 Remote Control / Trusted Device。
## 开关与缓解建议
### 1. 如果你的目标是关闭默认 analytics/telemetry
源码里明确支持以下限制:
- `src/utils/privacyLevel.ts:1-55`
- `src/services/analytics/config.ts:11-26`
建议:
- 设置 `DISABLE_TELEMETRY=1`
- 会进入 `no-telemetry`
- Datadog / 1P analytics 会被关闭
- 设置 `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`
- 会进入 `essential-traffic`
- 非必要网络流量会被进一步压缩
### 2. 如果你的目标是避免把本地目录和 git 信息送入模型
需要重点关注默认 prompt 链路,因为这部分不是传统“遥测”,而是模型上下文本身。
缓解思路:
- 在不敏感目录中运行,而不是直接在真实业务仓库根目录运行
- 避免在 `git user.name`、commit message、`CLAUDE.md` 中放入敏感标识
- 禁用或清理 `CLAUDE.md`
- 不启用 Remote Control / Bridge / Transcript Share / Feedback
### 3. 如果你的目标是避免 hostname 外发
避免使用:
- Remote Control / Bridge
- Trusted Device 注册 / 某些登录设备绑定流程
## 最终判断
从“是否采集本地系统信息并向外发送”这个问题本身看,答案是:
**是,存在,并且不止一条。**
但需要区分严重程度:
- **默认自动发生** 的,主要是:
- 模型请求中的环境/项目上下文
- analytics 中的环境/进程元数据
- **需要用户显式动作或特定功能开启** 才发生的,主要是:
- Feedback / Transcript Share
- Remote Control / Bridge
- Trusted Device
- OpenTelemetry
- ant-only `/insights`
- **未发现** 自动采集 MAC/IP/硬件序列号/机器唯一硬件 ID 的实现。
## 审计局限
- 本报告只基于本仓库源码,不包含第三方依赖内部实现的完全展开。
- 因此 GrowthBook `remoteEval` 被标为“高概率推断”,不是 100% 抓包确认。
- 如果你需要,我下一步可以继续补一版:
- 运行时抓包建议
- 外发域名清单
- 按“默认开启 / 可关闭 / 必须用户触发”生成一张更适合合规审查的表