Files
openclaude/docs/local-system-info-egress-audit.md
YoVinchen 5af8acb2bb 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
2026-04-09 14:09:44 +08:00

431 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 本地系统信息外发审计报告
- 审计时间: 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% 抓包确认。
- 如果你需要,我下一步可以继续补一版:
- 运行时抓包建议
- 外发域名清单
- 按“默认开启 / 可关闭 / 必须用户触发”生成一张更适合合规审查的表