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:
430
docs/local-system-info-egress-audit.md
Normal file
430
docs/local-system-info-egress-audit.md
Normal 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% 抓包确认。
|
||||
- 如果你需要,我下一步可以继续补一版:
|
||||
- 运行时抓包建议
|
||||
- 外发域名清单
|
||||
- 按“默认开启 / 可关闭 / 必须用户触发”生成一张更适合合规审查的表
|
||||
Reference in New Issue
Block a user