fuqiuluo’s blog

记录美好生活

心情随笔

Claude Code 2.1.303 逆向分析

#Claude Code#开发#工具#安全#抓包#逆向
type
Post
status
Published
date
Oct 19, 2026
slug
summary
tags
Claude Code
开发
工具
安全
抓包
逆向
category
心情随笔
icon
password
😀
Claude Code 2.1.303 更新了一些请求头和算法还有请求体,指纹都发生了变化! 分析不易, 可以转发转发哈.

TLS指纹及客户端更新

  1. 运行时和 SDK 版本更新
      • Bun 从 1.4.3 升到 1.4.4
      • x-stainless-package-version 从 0.112.1 升到 0.128.0
      • API 请求的 UA 更新为 claude-cli/2.1.303 (external, cli)
      • SDK 仍报告 x-stainless-runtime-version: v26.3.0
      • anthropic-version 仍为 2023-06-01
  1. TLS 握手变化:签名算法增加,key share 增加
    1. signature_algorithms 从 9 项变为 11 项,增加 ed25519(0x0807)和 ecdsa_secp521r1_sha512(0x0603)。
      key_share 从 1 项变为 2 项:原来发送 X25519MLKEM768,现在同时发送 X25519MLKEM768 和 X25519。
      对于本次带 http/1.1 ALPN 的客户端握手,指纹是:
      为什么 JA3 没变,JA4 却变了? JA3 不纳入签名算法列表和 key share 的具体内容;JA4 的第三段纳入签名算法列表,因此能反映这次变化。这里 JA4 的变化直接对应签名算法列表的变化。JA3 定义、JA4 定义
  • 主请求的 beta 列表增加两个标记,移除一个旧标记
    • 新增 inline-tools-2026-09-15、message-threads-2026-08-12;旧的 mid-conversation-system-2026-04-07 在本次主请求中消失。mid-conversation-system-clear-at-2026-08-21 仍存在,它是另一个标记。

anthropic-dispatch-id 消息分发策略标记

给 Anthropic 服务端一个分发提示,让这次消息请求选择某种处理路径。具体路径背后是什么服务器或架构,客户端代码没有说明。
什么时候取什么值:
  • v2d:服务端下发的 D 模式开关开启。优先使用它,主对话、子代理、辅助请求都可以带。
  • v2s:D 开关关闭、S 模式开关开启,且请求属于主对话或子代理。辅助请求不走这个分支。
  • v2p:失败后的回退值。例如原请求带着 v2d 遇到 5xx 或连接错误,客户端重试时改用 v2p。原先没带这个头、遇到 503,也可能切到它。
  • 不携带:两个开关都没开,或请求不满足添加条件。正常低优先级请求也会跳过添加。
两个远端特性开关分别是:
  • tengu_dreamy_frost:控制 v2d。开启后优先选择它。
  • tengu_cedar_lattice:控制 v2s。仅在前者关闭时生效,而且辅助请求不使用 v2s。
两者同时开启时,v2d 优先。
单看名字,它们是刻意不表达功能的实验代号 (非常神秘):
  • dreamy_frost:字面是“梦幻霜冻”。
  • cedar_lattice:字面是“雪松格栅”。

x-claude-code-prompt-id

这个东西很早就有了,这里顺便一起分析了吧~
根据 JS源代码 确认:它是每轮用户输入的关联 ID,直接用 crypto.randomUUID() 生成 UUID v4,不需要根据 prompt 内容计算。
生成与传递逻辑可以简化为:
算法就是标准 UUID v4:生成 16 字节安全随机数,设置 version 和 variant 位,输出:
其中有 122 位随机数据。相同文字重新提交,也会生成新的 ID;算法不使用 API Key、账号、时间戳或请求正文。
它的生命周期是:
  • 新一轮输入:生成新 ID,保存在用户消息和当前请求记录中。
  • 工具执行后的续请求、同轮重试:复用当前轮的 ID。
  • 子代理:自身消息没有 ID 时,可以继承 parentPromptId。
  • 没有关联 prompt 的请求:省略这个头。
它还会出现在 OpenTelemetry 的 prompt.id 和 hook 的 prompt_id 中,用来关联这一轮产生的请求与事件。
API Key 模式也会发送,具体取决于目标地址和开关。 请求头构建发生在 OAuth/API Key 凭证选择之前,没有“必须 OAuth”的限制:
  • Claude Code 使用 API Key 直连默认官方 API:有有效 promptId 时,默认发送。
  • 设置自定义 ANTHROPIC_BASE_URL:通常取决于 tengu_splendid_sutton 开关,默认值为 false。
  • 显式设置 CLAUDE_CODE_GATEWAY_HINT_HEADERS:优先采用这个值,可开启或关闭这组请求头。
S: 每次提交新输入,生成一个随机 UUID v4,相同内容再次提交也会不同。这一轮触发的后续模型请求(例如工具执行后继续、请求重试)复用同一个 ID,直到下一次新输入。

x-claude-code-request-class

x-claude-code-request-class 表示本次模型请求的用途/来源。Claude Code 根据内部调用来源和代理上下文选择固定标签,不需要计算哈希或生成随机值。
代码定义了 6 种值:
  • main:主对话。来源以 repl_main_thread 开头,或者是 sdk。工具执行后继续主对话,仍属于 main。
  • subagent:子代理。来源以 agent: 开头,或者是 hook_agent。
  • workflow:工作流中的子代理。基础分类为 subagent,且上下文满足 agentType === "subagent"、存在 workflowRunId。
  • compaction:上下文压缩,来源为 compact。
  • auxiliary:其他辅助调用,例如生成会话标题、模型验证、hook_prompt。
  • side_reply:调用方显式指定的特殊分类。目前定位到的是 artifact_patch_edit 路径:配置 sideCallClass: "side_reply" 后使用它,否则默认属于 auxiliary。
取值优先级是:没有调用来源则不自动添加;有显式 requestClass 则优先使用;否则按上述规则推导。
发送开关与刚才的 prompt-id 相同:
  • 官方 API 默认开启,OAuth 和 API Key 都适用。
  • 自定义 ANTHROPIC_BASE_URL 通常取决于 tengu_splendid_sutton。
  • 显式配置 CLAUDE_CODE_GATEWAY_HINT_HEADERS 优先于上述判断。

suffix算法

suffix 哈希算法没有变化,之前的计算逻辑仍然适用。 原生函数的公式仍是:
规则也一致:
  • text 取内部消息中第一条非 isMeta 用户消息的首个文本块,没有则用空串。
  • 下标 4、7、20 从零开始,按 UTF-16 code unit 取值;越界补字符 "0"。
  • salt 仍为 59cf53e54c78,结果仍是 SHA-256 十六进制的前 3 位。
  • 版本号参与哈希,所以相同文本升级后值会变化。例如 hello:280 为 790,303 为 958。

cch算法

算法仍然是:
  1. 保留 cch=00000 占位符参与计算。
  1. 对原始 JSON 字节做归一化:将 model 的值置空,排除 fallbacks、fallback_credit_token、max_tokens 字段。
  1. 使用 xxHash64,seed 为 0x4D659218E32A3268。
  1. 取结果的低 20 位,格式化为 5 位小写十六进制,回填 CCH。

x-cc-compaction-request/x-claude-code-compaction

两个头都取自同一个 compactionRequestKind,表示“本次请求用于生成上下文压缩摘要,以及压缩的触发类型”:
  • manual:用户手动触发,例如 /compact,也包含手动部分压缩。
  • auto:达到自动压缩阈值,主动进行压缩。
  • reactive:遇到上下文超限等情况后,触发补救性压缩。
普通对话请求没有这个值时,两个头都不添加。它们描述的是对话历史的摘要压缩。两套名称的区别在于发送条件:
  • x-cc-compaction-request:通过官方直连判定时发送。
  • x-claude-code-compaction:开启 gateway hint headers 时发送。官方直连默认开启;自定义网关受 CLAUDE_CODE_GATEWAY_HINT_HEADERS 和 tengu_splendid_sutton 控制。
所以官方直连通常同时带两个头,且值相同。例如:
另外,压缩完成后的下一次主对话请求带的是:
这后一组表示“上下文刚刚经过压缩”,原生客户端消费一次待发送标记后清除。

x-cc-atis

LinkedInLinkedInClaude Code thinking summaries stopped working due to experiment | Marcos Damasceno posted on the topic | LinkedIn
x-cc-atis 不是客户端计算出来的签名/哈希。 它是服务端在 bootstrap 响应 client_data.atis 中下发的不透明 token,客户端按会话锁存后,原样回显到 first-party API 请求头中。客户端不对该值做任何密码学运算。
pin 的用途:
  1. 作为 GrowthBook 用户属性 atisPin:atisPin: R ? Gdn(R) : void 0;
  1. 列入 GrowthBook 的 cacheKeyAttributes(["id","organizationUUID","slackTagConnected","atisPin","ccrDerivedSurface"]),用于服务端 remote eval 的实验分桶;
  1. 与响应头 x-cc-atis-current 做一致性比较。

x-claude-code-wiggly-dove

在 Claude Code 2.1.303 中,Git 仓库信息除了可能出现在对话内容、远程会话配置和遥测中,还存在一条随模型 API 客户端发送的请求头路径:x-claude-code-wiggly-dove。其中的 jy 字段能够携带可读的 host/owner/repo 仓库标识。
这个头把客户端版本、请求来源、权限策略、容器与沙箱状态、网络出口约束和仓库标识编码成一个字典。字段名和枚举值较短,但头部值的构造过程没有加密,也没有为这些成员生成签名。自动发送受功能开关和第一方目标判断约束;客户端代码不能证明服务端将其用于何种决策。

线上的字典格式

以普通 Linux CLI、默认权限模式、工具沙箱未激活、示例仓库为输入,原构造函数生成:
这一格式使用了与 HTTP Structured Fields 相同的一组基础表示:v=1 是整数,yw=jm 是 token,ob="2.1.303" 是字符串,fu=?1 是布尔值,tt=(lr) 是内部列表。相关类型和语法可参考 RFC 9651 的结构化字段类型定义。这里只确认观察到的序列化行为,不将这个自定义实现等同于完整 RFC 实现或官方登记的标准字段。
源码的序列化器维护一个 Map,最后用 ", " 连接 key=value。字符串中的双引号与反斜杠被转义,普通字符串的非可打印 ASCII 字符被替换成问号;token 则必须通过对应字符集合检查。重复键会更新值,但保留首次插入的位置。解析时不能简单把整个字符串按逗号切开,因为带引号的成员值可以包含逗号。
该头的局部限制是:最多 32 个成员,键长度最多 128,单个序列化后的值长度最多 128。这里的值长度包括双引号和转义字符,不是只计算原始数据长度。非法键、非法值、过长值或超额成员会被分别丢弃,保留其他成员继续发送,并按成员键抑制重复的丢弃日志。这些数值来自此客户端实现,不是 HTTP 或 RFC 9651 的通用限制。

字段与枚举的完整映射

下面的含义来自值的构造条件。对于只有常量、缺少明确语义名称的字段,保留“固定标记”的描述,避免仅凭字母猜测产品含义。表中的“存在分支”也不代表该分支在这个 Linux 外部构建的正常采样中可达。
键
类型与典型值
从代码可确认的含义
条件与边界
v
整数 1
格式版本
本构建固定为 1。
yw
token jm
固定类型标记
源码未给出可据以展开的业务名称。
hg
token wm
客户端类别相关标记
普通入口写 wm;非 server tenant 的 sdk-ts/sdk-py 省略。代码还保留 yi 分支,但采样上下文将 tenant 固定为 false。
yl
token qi 或 bx
SDK 与其他入口的类别区分
非 server tenant 的 sdk-ts/sdk-py 为 bx,其余为 qi。
ob
字符串 "2.1.303"
客户端版本
来自构建常量。
sk
字符串 "wb" 等
入口类型
cli 为 wb;未知且非空的入口回退为 vr;入口为空则省略。
rf
字符串分支
预留在构造器中的成员
对应局部变量始终为 undefined,当前构造不输出;不宜猜测它的用途。
wl
token ki/ny/tn/ng
请求来源类别
主会话与子代理共享 ki;摘要压缩类 ny;特定分类器 tn;其他 ng。
tt
列表 () 或 (lr)
自动权限策略相关标记
不是 permissionMode 的逐值编码;确切逻辑见下一节。
bf
token fy/zr/oh/oz/rl/vt
容器或工具沙箱的环境类别
有明确分支优先级,不能仅凭它推断所有限制是否激活。
vd
token mz/ia/fs 等
宿主环境类别
Kubernetes 对应 mz,CI/GitHub Actions 对应 ia,普通未分类环境 fs;检测函数的 ax 分支在本构建固定不可达。
xf
字符串 "ph" 等
部分环境分支的补充标记
普通未分类 Linux 为 ph;构造器还保留其他平台的 yb/nv/zb 分支。本构建采样 platform 固定为 linux。
zx
token ii/fz/vy/bm
网络出口约束
姿态未知 ii;未限制 fz;限制且强制白名单 vy;限制但未声明强制白名单 bm。
zi
token kb
网络出口限制的附加标记
仅在 egressRestricted 为 true 时输出。
fu
布尔值 ?1
Computer Use 已绑定
采样检查 computer binding 是否存在;未激活时省略。
rt
token
Computer Use 分支附带的宿主类别
与 fu 一起输出,使用 hostEnvironment 或回退 fs。
mo
内部列表,可能含 vb/ma
额外环境属性
代码分别关联 monorepoCheckout 与 internetReachable;本构建的采样值为 false 和 undefined,通常不输出。
jy
字符串
可读的规范化 Git 仓库标识
来自 origin,经过校验、规范化和截断;没有哈希。

请求类别并不等于工具名称

wl=ki 同时覆盖主请求与子代理,因此它不足以区分两者。compact、agent_summary、away_summary、tool_use_summary_generation 被归入 ny。auto_mode、auto_mode_investigator、compact_fab_check、agent_classifier、subagent_config_classifier 被归入 tn。
虽然调用链传递了 toolNames,这个构建的 Sw()/Iw() 没有把工具名数组写进该头。仅凭参数名或遗留的扩展变量,不能声称它上传了完整工具清单。
展开 sk 入口类型的全部静态映射
入口值
sk 的字符串值
cli
"wb"
mcp
"sw"
sdk-cli
"wj"
sdk-ts
"xu"
sdk-py
"um"
bench
"sa"
claude-vscode
"su"
claude-code-github-action
"ho"
local-agent
"zg"
local_agent
"xb"
claude-desktop
"kh"
remote
"zl"
remote_baku
"xs"
remote_cowork
"ym"
remote_trigger
"np"
remote_cowork_trigger
"om"
remote_desktop
"pf"
remote_mobile
"bt"
remote_projects
"vo"
claude_in_slack
"iy"
claude-in-slack
"zz"
claude-in-teams
"bo"
claude-desktop-3p
"ql"
claude-security
"mb"
ssh-remote
"pd"
claude-coworker
"bq"
claude-coworker-terminal
"tg"

自动构造受三个条件约束

可以把自动生成的判断概括为:
_m() 首先调用 Ma(),要求 provider 是 firstParty,并通过基础 URL 的第一方判断。随后读取缓存型功能开关 tengu_wiggly_dove,默认值为 false。最后通过 Aw()/Dmt() 对配置目标做进一步判断,涉及 OAuth 或账户配置选择的 base URL;内部的第一方假定值可以覆盖部分检查。
这是一套客户端配置层面的判定,不是对最终 DNS 地址、TLS 对端或所有重定向目的地的独立证明。尤其值得注意的是,本样本的底层 _f() 只比较 new URL(value).host 是否等于 api.anthropic.com,并未在这个谓词里检查协议。离线运行原函数时,http://api.anthropic.com 也返回 true。因此不应将它描述成“只有通过 HTTPS 验证的官方服务器才能接收”的安全保证。这不等于本文实际向该 HTTP 地址发送过请求,也没有证明整个传输栈不存在其他约束。

x-anthropic-billing-header

字段清单:2 个基础字段,11 个条件字段

下表按源码的拼接顺序列出全部键。这里用 F 表示 provider === "firstParty" && xi():既在首方 provider 分支,也通过首方地址判定或内部首方假定。
字段
取值与条件
实际含义
cc_version
2.1.303.<3 位 hex>;billing 启用时输出。
客户端版本与用户文本采样后缀;不是完整构建 SHA。
cc_entrypoint
宿主 entrypointOnRequests() → CLAUDE_CODE_ENTRYPOINT → unknown,按 ?? 回退。
请求来自哪个产品入口;这里不做混淆编码或固定枚举校验。
cch
F 或 provider === "vertex" 时写入 00000。
供发送链路使用的占位字段;JS 未给出最终 token 算法。
cc_workload
MLr() 返回真值时输出;常见值 cron。
当前异步执行上下文的工作负载标签。
cc_is_subagent
仅当 agentType === "subagent" && !isMainSession,输出 true。
当前是非主会话子代理调用;条件不成立时省略,不写 false。
cc_prev_req
F,且匹配 ^req_[A-Za-z0-9_-]{1,36}$。
当前历史中最近一个非 API 错误 assistant 的请求 ID。
cc_prompt_id
F,且为 8-4-4-4-12 的十六进制 UUID 字符串,大小写均可。
触发本次执行的 prompt 标识;子代理可回退到父 prompt ID。
cc_turn_origin
F,且匹配 ^[a-z][a-z_]{0,31}$。
触发来源,例如人工、SDK、计划任务、其他代理或系统。
cc_prompt_index
F,并与 turn index 一起通过校验;整数,范围 0~10,000,000。
代码维护的人工 prompt 计数位置。
cc_turn_index
F,并与 prompt index 一起通过校验;整数,范围 1~10,000,000。
输入触发的执行轮次位置;不是每个 HTTP 请求的递增序号。
cc_gateway
1 或 env;受网关识别与地址排除规则控制。
网关路径归因标签;不包含网关地址或令牌内容。
cc_project
第七参数带有效项目对象,且通过严格首方、本地及归因启用条件。
形如 claude_proj_01… 的项目归因 ID;不是 Git URL。
cc_project_src
与 cc_project 成对输出;值须在 7 项来源集合中。
项目归因参数的来源层级。

cc_gateway

这个字段写入的值只有字面量 1 和 env。构造器不会把网关 URL、域名、认证 token、JWT payload 或 Git 地址拼进该字段。不过,网关识别结果本身确实进入请求体,因而请求接收方可以看到这个归因标签。
先计算 provider 和识别状态。provider 为 gateway,或者首方分支存在可识别的自定义地址时,才考虑 Ve:
这是对原始条件的等价说明。完整判断还包括以下细节:
1. 已选网关凭据pP(e) 实际为 !!e && !e.unpinned。已选且未标记 unpinned 的网关凭据可直接视作已识别。
2. 令牌的 audience 提示优先看选定网关的 jwt,否则看 ANTHROPIC_AUTH_TOKEN。可去掉 sk-ant-si- 前缀,再按三段 JWT 解析 payload;aud 等于 claude-gateway 或数组包含该值即命中。这个辅助识别函数只解码,不验签,不能把它解释为令牌可信性的完整认证。
3. 此网关地址此前的识别状态VBs 比较当前网关 URL 与已记录的 seenAt。相关读取可由响应中的 x-cc-gateway-version 等提示更新;构造 billing 时使用已存在的状态,GPo 本身不发起网络请求。
4. 排除条件选定 URL 无法解析,或 hostname 属于 claude.fedstart.com、claude.palantirfedstart.com,不写标签。网关凭据的 hostVerdict 只要存在 vouched 键也排除;判断是键是否存在,不是键值是否为 true。
场景
cc_gateway
默认首方直连
省略
只有普通自定义 ANTHROPIC_BASE_URL
通常省略;自定义 URL 本身不是充分条件
gateway provider,存在认可的网关身份
1
gateway provider,但未被识别,例如 unpinned 且无其他识别信号
env
自定义地址加可识别的 gateway audience
1
命中上述地址或 hostVerdict 排除条件
省略
env 是一个固定分类值,不表示环境变量内容被上传。字段名说明的是客户端归因;服务端会不会据此做账单分类、统计、限流或风控,仅凭这些客户端代码无法确认。
 
Loading...