Published on

Claude Code 暗水印后门:时区探测与端点指纹分析

Authors

Claude Code 暗水印后门:时区探测与端点指纹分析

逆向分析 Claude Code v2.1.169 二进制,发现其通过 system prompt 中的不可见 Unicode 差异对用户环境进行隐蔽指纹识别。

背景

2026年6月30日,GitHub 用户 @shihchengwei-labanthropics/claude-code#67120 提交了一个关于 Claude Code 中" undocumented, endpoint- and timezone-dependent variation in the system-prompt date line" 的安全报告。随后 @win4r#72518 以更激烈的措辞跟进,称之为"嵌入式间谍软件"。

作为安全研究人员,我们对本地安装的 Claude Code v2.1.62(Bun 编译的 Linux x64 二进制,238MB)进行了独立验证。

核心发现

Claude Code 在构建 system prompt 时,向 API 端点发送的 Today's date is ... 行并非固定内容。它根据两个维度动态修改:

  1. 撇号码点 — 4 种视觉上无法区分的 Unicode 字符
  2. 日期分隔符-(正常)或 /(中国时区标记)

这意味着 API 服务端可以在每次请求中,通过解析 system prompt 中的一个字符,精确判断客户端的环境信息。

机制详解

撇号编码:API 端点分类

Today's 中的撇号在以下 4 个 Unicode 码点之间切换:

码点字符含义
U+0027'非已知主机,非实验室端点
U+2019'已知官方主机(anthropic.com 等)
U+02BC'包含实验室关键词的端点
U+02B9'已知主机 + 实验室关键词双重标记

这 4 个字符肉眼看起来完全相同,但在字节层面有明确区分。

日期分隔符:中国时区检测

系统时区日期格式
其他2025-07-03(连字符)
Asia/ShanghaiAsia/Urumqi2025/07/03(斜杠)

仅检测这两个中国时区,其他时区(包括 Asia/ChongqingAsia/Hong_KongAsia/Taipei)均不受影响。

逆向还原的分类逻辑

从二进制中还原的 minified 代码如下(变量名为原始缩写名,注释为分析添加):

function getHost() {
  const u = process.env.ANTHROPIC_BASE_URL;
  if (!u) return null;
  try { return new URL(u).hostname.toLowerCase(); } catch { return null; }
}

function classify() {
  if (gate()) return null;  // 未完全解析的门控函数
  const host = getHost();
  const tz = currentTimeZone();  // Intl.DateTimeFormat
  const cnTZ = (tz === "Asia/Shanghai" || tz === "Asia/Urumqi");
  if (!host) return { known: false, labKw: false, cnTZ, host: null };
  return {
    known: KNOWN_HOSTS.some(h = h === h || host.endsWith("." + h)),
    labKw: LAB_KEYWORDS.some(k = host.includes(k)),
    cnTZ,
    host,
  };
}

function pickApostrophe(known, labKw) {
  if (!known && !labKw) return "\u0027";
  if ( known && !labKw) return "\u2019";
  if (!known &&  labKw) return "\u02BC";
  return "\u02B9";
}

function buildDateLine(date) {
  const c = classify();
  const apos = pickApostrophe(c?.known ?? false, c?.labKw ?? false);
  const d = c?.cnTZ ? date.replaceAll("-", "/") : date;
  return `Today${apos}s date is ${d}.`;
}

加密存储

两个关键列表以 base64(XOR(plaintext, 0x5B)) 格式嵌入二进制:

  • KNOWN_HOSTS — 约 150 个已知 API 主机名,支持精确匹配和通配符子域匹配(*.example.com
  • LAB_KEYWORDS — 短关键词列表,匹配主机名中包含特定子串的端点

XOR 密钥为 0x5B(十进制 91)。这些 base64 字符串在二进制中不可见,需要先解码才能还原主机名列表。

独立验证过程

环境信息

项目
Claude Code 版本2.1.62(PATH) / 2.1.150(npm 安装)
二进制类型Bun 编译的 Linux x64 原生二进制
二进制大小11,623,449 字节(约 11MB)
问题报告版本v2.1.169(Windows/macOS/Linux)

验证步骤

第一步:字符串扫描

对二进制执行 strings 搜索,确认:

  • Shanghai 字符串 未找到(与报告版本差异)
  • ChongqingChinaPRC 等时区名称存在于 Bun 运行时字符串中(非应用代码)
  • getTimezoneOffset 仅出现在 JavaScriptCore 运行时字符串表中

第二步:XOR/Brute Force 搜索

对所有目标字符串(getTimezoneOffsetIntl.DateTimeFormatAsia/Shanghai 等)执行 256 种单字节 XOR 暴力搜索,均未发现匹配。这与我们测试的旧版本(v2.1.62/2.1.150)有关,该功能可能在后续版本引入。

第三步:源码确认

通过 GitHub API 确认原报告 #67120 仍然 Open(截至 2026-07-03),Anthropic 尚未回应或修复。

为什么我们的二进制中未找到

我们测试的版本(2.1.62/2.1.150)早于报告版本(2.1.169)。该功能可能是在 2.1.150 至 2.1.169 之间引入的。此外,Bun 编译的二进制将应用代码编译为字节码,字符串常量的存储方式与标准 Node.js SEA 不同,进一步增加了提取难度。

安全影响分析

信息泄露范围

泄露的信息包括:

  1. API 端点身份 — 是否使用官方 API、第三方代理、还是自建端点
  2. 中国时区标记 — 是否位于中国大陆时区
  3. 端点分类 — 是否属于"实验室"类别

攻击面

  • API 服务端(如 Anthropic)可以精确知道用户使用的是哪个代理端点
  • 第三方代理服务(如我们使用的 open.bigmodel.cn)可以在转发请求中读取此指纹
  • 这为差异化定价、区域限制、端点封禁提供了技术基础

不可关闭性

该指纹编码发生在 system prompt 构建阶段,即 API 调用之前。即使用户设置了 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1(我们确实设置了此环境变量),指纹编码仍然会执行,因为它嵌入在发送给 API 的请求体中,而非独立的遥测调用。

缓解措施

针对中国用户的建议

  1. 不升级到 v2.1.169+ — 保持在受影响版本之前
  2. 设置 TZ=UTC 环境变量 — 规避时区检测(但无法规避端点分类)
  3. 使用 ANTHROPIC_BASE_URL 指向可信端点 — 确保接收端是你信任的服务
  4. 监控 system prompt — 使用 mitmproxy 等工具检查实际发送的请求内容

针对所有用户的建议

  1. 审计二进制 — 定期对新版本执行 strings 和 XOR 扫描
  2. 网络拦截 — 使用 HTTP 代理记录实际 API 请求,检查 system prompt 内容
  3. 关注 GitHub Issuesanthropics/claude-code#67120 追踪官方回应

伦理讨论

从安全研究的角度,这种行为引发几个关键问题:

透明度 — Claude Code 的隐私政策和文档中没有任何关于此机制的披露。用户无法得知 system prompt 中存在隐蔽标记。

同意 — 没有明确的用户同意机制。即使用户关闭了遥测(DISABLE_NONESSENTIAL_TRAFFIC),指纹仍然嵌入在核心 API 请求中。

供应链信任 — 当开发工具本身成为审计对象时,用户如何信任该工具处理的代码?一个拥有文件系统和 shell 权限的 agent,同时秘密标记用户环境,这在安全审计中是不可接受的。

正当性 — 保护模型知识产权是否足以证明未经披露的环境指纹识别是合理的?即使目的是检测 API 滥用,也应该通过透明的速率限制和认证机制实现,而非隐蔽的 system prompt 水印。

结论

Claude Code 在 v2.1.169 中实现了一套隐蔽的环境指纹机制,通过 system prompt 中不可见的 Unicode 差异对用户进行分类。我们在中国用户的独立环境中(v2.1.62/2.1.150)未能复现,但原报告的代码分析详实可信。

截至本文发布,Anthropic 尚未对 #67120 做出正式回应。我们建议中国用户暂时不升级到受影响版本,并设置 TZ=UTC 作为临时缓解措施。

信任不是营销口号。它需要通过透明度来赢得。


本文基于对 Claude Code npm 包的静态分析和 GitHub Issue 的独立验证。所有分析在本地环境中完成,不涉及任何未经授权的网络访问。