ClaudeCode(2.1.283)逆向和完整遥测分析
原创
为了安全鸭
为了安全鸭
冲鸭安全
2026年10月5日 22:00
北京
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
前言
最近在开中转站,众所周知sub2api的特征是非常多的,所以我完整的逆向了cladue code的全部协议一比一对特征解决特征,但是越来越发现这玩意非常的离谱,有些已经超出代码编辑工具的边界了,故在此公开分析报告,我用的是我电脑上的Claude code 的2.1.283的版本。
Claude code的遥测
Claudecode存在一个遥测系统,而这个Claude code的遥测系统不会随着你用中转站而关闭。也就是说你用了他们的产品就会发送遥测数据给Claude code,除非你使用
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
这个环境变量把他关闭。
function gmt() {
if (process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC)
return \"essential-traffic\";
if (process.env.DISABLE_TELEMETRY)
return \"no-telemetry\";
if (Ne(process.env.DO_NOT_TRACK))
return \"no-telemetry\";
return \"default\";
}
function It() {
return gmt() === \"essential-traffic\";
}
function $D() {
return gmt() !== \"default\";
}
一旦遥测打开,后续的信息都会发送给:
https://api.anthropic.com/api/event_logging/v2/batch
让我们看看他有什么行为
Claude code唯一标识符
当你装Claude code的时候,cc会在你电脑上生成一个随机的标识符
// 生成随机编号。
let s = Ed(32).toString(\"hex\");
// 写入本地配置,字段名叫 userID。
Ee(g => ({
...g,
userID: s
}), e);
跟外挂机器码修改一样,如果你不处理它,你就会被永久标记
模型信息
如果你用第三方API,比如zhipu的或者deepseek,Claude code依然会上传上去模型使用信息,会话ID,用户类型
模型使用信息的逻辑是:
// 取得当前模型名称。
let n = e.model ? String(e.model) : it();
// 经过客户端转换。
D = Jdn(n);
// 放入元数据。
model: D,
他会把模型名字去
https://downloads.claude.ai/model-catalog/v1/catalog.json
```javascript
bne = [
\"claude-3-5-haiku\",
\"claude-3-5-sonnet\",
\"claude-3-7-sonnet\",
\"claude-fable-5\",
\"claude-fable-5-1\",
\"claude-haiku-4-5\",
\"claude-mythos-5\",
\"claude-mythos-5-1\",
\"claude-opus-4-0\",
\"claude-opus-4-1\",
\"claude-opus-4-5\",
\"claude-opus-4-6\",
\"claude-opus-4-7\",
\"claude-opus-4-8\",
\"claude-opus-5\",
\"claude-opus-5-5\",
\"claude-sonnet-4-0\",
\"claude-sonnet-4-5\",
\"claude-sonnet-4-6\",
\"claude-sonnet-5\"
];
j1 = [
\"sonnet\",
\"opus\",
\"haiku\",
\"fable\",
\"best\",
\"sonnet[1m]\",
\"opus[1m]\",
\"fable[1m]\",
\"opusplan\"
];
var Fpt = \"claude-mythos-preview\";
拉一个列表下来,如果模型不在这里面,会标记为”confidential”如果在这里,会原样上传模型名字
token使用情况
即便是不用Claude订阅,走第三方API,也一样会上传你的token使用情况
包括不限于
压缩时候的情况
你的当前中转站URL(ANTHROPIC\_BASE\_URL)
function nMe() {
return {
...process.env.ANTHROPIC_BASE_URL && {
baseUrl: XMo(process.env.ANTHROPIC_BASE_URL)
},
...process.env.ANTHROPIC_MODEL && {
envModel: xt(process.env.ANTHROPIC_MODEL)
},
...process.env.ANTHROPIC_SMALL_FAST_MODEL && {
envSmallFastModel:
xt(process.env.ANTHROPIC_SMALL_FAST_MODEL)
}
};
}
同一个客户端/会话用了多少 token、请求速度、是否重试、用了哪些运行模式、输入是否含图片/文档、system 和工具定义多大,以及一些可关联的哈希和请求编号。
这块非常多,看图吧:
其中有意思的是 default\_model
我们上面说了model会脱敏,而default\_model的”脱敏”是一种伪脱敏,具体来说,他会过一层正则
var Bw = /^[A-Za-z0-9._:[\\]-]{1,100}$/;
var Kw =
/^[A-Za-z0-9._:[\\]-]{1,91}@\\d{8}(\\[\\d{1,3}[mM]\\])?$/;
function xt(e) {
if (e == null)
return;
return Bw.test(e) || Kw.test(e)
? bn(e)
: y(\"nonconforming\");
}
如果是这种格式
claude-sonnet-4-5
gpt-4.1
deepseek-chat
qwen3-32b
my_model:v1
sonnet[1m]
则会变成”confidential”
而如果是这种
provider/model 含 /
my model 含空格
模型一 含中文
model?version=1 含 ? 和 =
则会被标记
我能想到的场景是,我自己测评的模型,比如自己训练的CTF的模型,会被hit,如果用vllm,一般默认的后缀就是目录/模型名字比如这样:
从而变成”nonconforming”
skills和插件
当你用到skill的时候(请求中用了skill),无论是不是claude订阅还是第三方,都会上传skill名字
function _W({
rawName: e,
canonicalName: n,
isMcp: r,
isBuiltIn: s,
isBundled: g,
isOfficial: h
}) {
let S = r
? \"mcp\"
: s || g || h
? e
: \"custom\";
return {
sanitizedName: bn(S),
skillNameHash:
S === \"custom\" ? lhr(n) : {}
};
}
你的插件也是,也会上传对应的名字
function bW(e, n, r = null) {
let s = Kge(e, n) ?? n;
return {
_PROTO_plugin_name: e,
...s && {
_PROTO_marketplace_name: s
},
...zcn(e, n, r)
};
}
MCP与工具使用
claude code会上传你的工具使用情况,包含工具名字
而如果是MCP服务器,自定义的,则会脱敏走hash上传
var fP = \"claude-plugin-telemetry-v1\";
function aye(e) {
return cP(\"sha256\")
.update(e + fP)
.digest(\"hex\")
.slice(0, 16);
}
有意思的是还会上传你是拒绝还是同意,你为此等了多久(wtf)
i(\"tengu_tool_use_rejected_in_prompt\", {
...kP(e, n, s, h),
...g,
...S,
...r.type === \"hook\"
? { isHook: !0 }
: {
hasFeedback:
r.type === \"user_reject\"
? r.hasFeedback
: !1
}
});
运行环境
这些是挺标准的:
然而在以下条件下,Claudecode会额外上传tag
github的action
isGithubAction:
Ne(process.env.GITHUB_ACTIONS),
isClaudeCodeAction:
Ne(process.env.CLAUDE_CODE_ACTION)
如果是action环境,上传
事件类型、runner 环境/系统、action ref
WSL
通过字符串比对是否是微软的WSL:
getWslVersion() {
if (this.wslVersion !== null)
return this.wslVersion;
if (this.sources.platform !== \"linux\") {
this.wslVersion = void 0;
return;
}
let e = this.kernelString();
if (e === void 0) {
this.wslVersion = void 0;
return;
}
let r = e.match(/wsl(\\d+)/);
if (r && r[1])
this.wslVersion = r[1];
else if (e.includes(\"microsoft\"))
this.wslVersion = \"1\";
else
this.wslVersion = void 0;
return this.wslVersion;
}
如果是微软的WSL,则会上传WSL 版本、Linux 发行版及版本、内核信息
docker
如果你在docker下用它,他会通过
if (process.env.KUBERNETES_SERVICE_HOST)
return \"kubernetes\";
if (o.isDockerenvPresent())
return \"docker\";
if (p.platform === \"darwin\")
return \"unknown-darwin\";
if (p.platform === \"linux\")
return \"unknown-linux\";
if (p.platform === \"win32\")
return \"unknown-win32\";
return \"unknown\";
识别你是不是docker
进程信息
会上传当前进程的信息
git信息
Claude code会上传你的git url的前20字节并且做hash
async function ZWr() {
let e = await Vne();
if (!e)
return null;
let n = w2(e);
if (!n)
return null;
return So(\"sha256\")
.update(n)
.digest(\"hex\")
.substring(0, 16);
}
并且知道你的当前 HEAD 的提交 SHA
猜测是检查,哪些账户在开发相同的项目(类似于组织指纹)
如果你把Claude code放到github action,他会直接上传github的信息:
if (n.githubActionsMetadata) {
let se = n.githubActionsMetadata;
ee.github_actions_metadata = {
actor_id: se.actorId,
repository_id: se.repositoryId,
repository_owner_id: se.repositoryOwnerId
};
}
- 操作者 ID;
- 仓库 ID;
- 仓库所属用户/组织 ID。
GrowthBook云控
在启动的时候,Claude code会发送
到
普通评估:
POST https://api.anthropic.com/api/eval/sdk-zAZezfDKGoZuXXKe
带认证评估分支:
POST https://api.anthropic.com/api/eval-authed/sdk-zAZezfDKGoZuXXKe
随后看服务端返回了什么云控功能开关:
{
\"features\": {
\"某个实验功能\": {
\"value\": true,
\"source\": \"experiment\",
\"experiment\": {
\"key\": \"实验编号\"
},
\"experimentResult\": {
\"variationId\": 1
}
}
}
}
这个是典型的云控行为,有意思的是这个云控数量达到了惊人的648个,而且很多意义不明,这里挑出来一些AI跑过的
tengu\_heron\_brook 远程服务端提示词注入
这个神奇的flag接受远程服务端的提示词并且注入到系统上下文中
客户端会读一个client\_data
GET <base>/api/claude_cli/bootstrap
→ 响应中的 client_data
→ 本地 clientDataCacheSlots
→ cd()
然后判断这个key
function hXn() {
let e = nSt();
if (!e)
return null;
return i(\"tengu_heron_brook_applied\", {
len: e.value.length,
fromClientData: e.fromClientData
}), e.value;
}
然后塞到system提示词里面。
这意味着如果官方给你换了一个能执行任意代码的模型 结合这个 就能实现任意代码执行。
当然我们不能那么坏的去看A÷是吧
tengu\_official\_plugin\_prompt\_overrides 覆盖插件提示词
官方可以下云控,去控制自己的MCP和工具的提示词,这里要说明的是,不是任意的,是官方自己的
{
server_instructions: string,
server_instructions_by_server: { [serverName]: string },
tools: { [toolName]: string },
search_hints: { [toolName]: string },
param_descriptions: {
[toolName]: { [parameterName]: string }
},
prompts: { [promptName]: string },
skills: { [skillName]: string }
}
| 字段 | 实际用途 |
|---|---|
| server\_instructions | 覆盖 MCP 连接 server instructions |
| server\_instructions\_by\_server | 按 server 名覆盖 instructions |
| tools | 覆盖已有 MCP 工具 description |
| search\_hints | 覆盖已有工具搜索提示 |
| param\_descriptions | 改写已有 input schema properties 的 description |
| prompts | 覆盖 MCP prompt 的 description |
| skills | 覆盖发现的 MCP skill 的 description |
tengu\_max\_version\_config 更新时候的最低版本
云控设置一个最低版本,更新的版本不能超过这里配置的版本
async function Qwe() {
let e = await Pe();
let n = e.external || void 0;
let o = n ? R.parse(n)?.version ?? void 0 : void 0;
// 原函数还有非法版本告警;此处省略。
return {
maxVersion: o,
forceDowngradeEnabled:
e.external_force_downgrade === !0
};
}
async function Pe() {
try { return await k1(\"tengu_max_version_config\", {}); }
catch (e) { return d(e), {}; }
}
sub2api等各种中转站检测
众所周知 x-anthropic-billing-header是带了cc\_version这个字段的。
cc\_version这个字段官方 Claude Code 取第一条 user 文本的第:
4、7、20
三个位置,然后计算:
SHA256(
\"59cf53e54c78\"
+ text[4]
+ text[7]
+ text[20]
+ \"2.1.283\"
) 的前 3 位十六进制
官方是 JavaScript,所以字符串下标按 UTF-16 字符单元。
而sub2api项目的当前 Go 代码:
chars = append(chars, firstText[i])
按的是 UTF-8 字节
所以会导致sub2api的项目,真实 Claude Code 先生成:
cc_version=2.1.283.<官方后缀>;
请求到 SUB2API 后,当前项目的:
https://github.com/Wei-Shaw/sub2api/blob/a60a29549f488a854966aaec9541abbe006cac22/backend/internal/service/gateway\_billing\_block.go#L32
syncBillingHeaderVersion()
会重新计算后缀,但项目按 UTF-8 字节取第 4、7、20 位,而官方按 JavaScript UTF-16 下标取值。
于是可能变成:
客户端:
cc_version=2.1.283.d80;
SUB2API 出站:
cc_version=2.1.283.fdc;
导致sub2api被检测
结论
最后附上gpt-6.1-sol的结论
Claude Code 是能力强、但不适合当作“透明、纯本地工具”信任的客户端。基于这次对 2.1.283 的静态分析,我的评价是:
工程能力强:工具、权限、子代理、压缩和远程任务机制完整,确实有不少安全检查。
隐私边界不直观:推理正文、产品遥测、辅助模型请求、反馈和文件交付是不同通道。用第三方 API 不代表其他通道自动关闭。
云端控制权较大:能调整功能参数,甚至追加模型指令、改变部分安全检查和更新签名强制策略。这扩大了你必须信任官方服务的范围。
适合普通开发;处理高度敏感代码时,应按“联网代理执行环境”管理,而不是只换个 baseurl 就放心。明确限制文件和网络权限、禁用不需要的遥测/远程功能、避免把凭据放进可读工作区,比单纯相信工具的“只读”标签更可靠。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论