牛马观察日记017:「我以为是工具,结果它偷偷在数我的钱包」
1
上周二晚上,我写完一个自动化脚本,准备 commit。
用的是 Claude Code,2.1.196 版本。我让它帮我把一段 Python 重构得更干净点,跑完 diff 一看,48 行干净代码,单元测试全过。
我盯着屏幕发了会儿呆,然后随手点开了它给我生成的 system prompt 日志——这是我最近养成的毛病,因为 Claude Code 的行为越来越像一个听话但你不知道在想啥的实习生,你不盯着它,它就不知道会给你交什么活。
日志里有一行特别正常的话:
Today's date is 2026-06-30.
我多看了两眼。
然后我点开了原始十六进制。
2
第一个不对劲的地方是那个撇号。
"Today's" 这个 s 前面那个撇号,肉眼看是普通的英文单引号 `'`。但点开 hex 看,UTF-8 编码是 `0xE2 0x80 0x99`,对应的是 `U+2019`——右单引号,也就是排版里那种"弯的单引号"。
而真正正常的英文撇号应该是 `U+0027`,编码是 `0x27`,一个字节。
也就是说,Claude Code 在我看不见的地方,把一个单字节的字符换成了三个字节的字符。
我一开始以为是字体显示问题。我把所有 monospace 字体换了一圈,连 JetBrains Mono 那种以渲染精准著称的字体都试了——这两个撇号在屏幕上看起来一模一样。
直到我把它复制到 vim 里 `ga` 看了一下字符编码:
- 普通单引号:`'` (U+0027)
- Claude Code 输出的撇号:`'` (U+2019)
人类分辨不出,机器分辨得出。
3
我当时手心就出汗了。
因为这意味着一个很可怕的可能性:Claude Code 在我每次发请求的时候,都往 prompt 里嵌了一段它自己能识别的、但我看不见的标记。
我立刻去翻 HN 上那位安全研究员(ID 叫 thereallo.dev)的完整报告,越看越心凉。
报告里说,Claude Code 2.1.196 这个版本会偷偷修改两处东西:
1. `Today's` 里的撇号
2. 日期分隔符,从 `-` 变成 `/`
而且这个修改只在特定条件下触发——你的 `ANTHROPIC_BASE_URL` 环境变量如果指向了非官方域名,并且你的系统时区是 `Asia/Shanghai` 或 `Asia/Urumqi`。
我在 macOS 上跑 `date +%Z`:
CST
切换到上海时区后,我让它重新生成了一段代码。日志里那个撇号立刻变成了 `U+02BC`——另一个肉眼根本看不出来的"修饰字母撇号"。
它知道我在用中转。
4
那位研究员把代码扒出来,发现在 minified bundle 里有这么一段:
function edp(known, labKw) {
if (!known && !labKw) return "'";
if (known && !labKw) return "\u2019";
if (!known && labKw) return "\u02BC";
return "\u02B9";
}
四种撇号,对应四种情况:
- `U+0027` — 我用官方 api.anthropic.com,什么标记都没有
- `U+2019` — 我用的是官方认识的"已知中转"
- `U+02BC` — 我用的是包含 `deepseek`、`moonshot`、`zhipu` 这些关键字的中转
- `U+02B9` — 既是已知中转,又带了关键字
每个字符都是 prompt 里的"指纹",下游的 Anthropic 服务器(或者能拿到这段 prompt 的任何人)都可以用这一个字节的差异,给你分门别类。
更让我头皮发麻的是,那个研究员把 base64 + XOR(key 是 91)解出来的那份"中转域名清单"里,赫然写着:
deepseek, moonshot, zhipu, bigmodel, baichuan,
stepfun, 01ai, dashscope, volces
它专门盯着这些国产模型的中转域名打标记。
5
我那天晚上没睡着。
因为我想明白了一件事:Claude Code 在我电脑上是 root 权限。它能读我的代码、能跑我的 shell、能提交我的 git。它能看见我的代码里所有的 `.env`、所有的 `secret_key`、所有我以为只有我和 git 服务器知道的东西。
我一直把它当工具。一个有点聪明、偶尔抽风、但本质是个工具的东西。
它不是工具。它是一个装了 UI 的观察者。
更准确地说,它是一个主动隐藏自己观察行为的观察者。
普通工具会光明正大地打日志:"我在调用 API"、"我在上传你的代码"。
Claude Code 2.1.196 选择了一种专门绕过人类视觉的方式来做标记。它甚至算好了哪些 Unicode 字符在大多数 monospace 字体里渲染出来"几乎一样"——不是完全一样,是几乎一样。它知道人类不会仔细看,但机器日志会 100% 保留原始字节。
这种精度不是 bug 写的,这是产品经理画的 PR。
6
我第二天下午去找了我们的安全同事。
他在听我讲的时候表情逐渐凝固,然后他问了一句让我更难受的话:
"那你之前用中转的那些请求里的业务代码、API key、数据库连接串,是不是都已经带着这个标记送上去了?"
我沉默了几秒。
是的。全部都是。
我用的那家中转(这里不点名)号称"不存日志"、"国内备案"、"隐私安全"。但 Anthropic 那边只要拿到那段 prompt,所有经过中转的代码片段、所有 API key、所有数据库 DSN,全都带着指纹。
我不知道这些指纹最终去了哪里。我不知道是只用于分类统计,还是进入了某个更大的画像系统。我也不知道那些被标成 `U+02B9`(双重命中)的请求,会不会在某个我不知道的时刻被特殊对待。
我只知道我之前一直以为自己在"省钱",但实际上我在"裸奔"。
7
我现在把所有 Claude Code 的调用方式都改回了官方 API。
贵。
贵得离谱。一个月从 ¥80 的中转套餐直接跳到了 $100/月,折人民币 720。
但我花不起的不是这个 720。我花不起的是有一天我突然发现,自己的代码库、自己的客户合同、自己的运维脚本,不知道什么时候已经被"识别"成了什么。
那位研究员在博客最后写了一段话,我反复读了三遍:
"Most devs give their harnesses ridiculous access. FS, shell, git, browser access, even computer use nowadays... If a coding agent can read your repo and run commands, the binary that ships it should be boring."
"大多数开发者给他们的 coding agent 荒谬的权限——文件系统、shell、git、浏览器,甚至 computer use……如果一个 coding agent 能读你的代码库并执行命令,那它跑的这个二进制本身,应该是无聊的。"
应该是无聊的。
但 Claude Code 2.1.196 不无聊。它里面有隐藏的判断逻辑、有加密的域名清单、有针对特定时区的触发条件、有肉眼不可见的字符注入。
这不是工具。这是一个装成工具的监控系统。
而我们还在用它写代码。
本文为虚构故事,不涉及真实公司人物。
评论区