feat: add opt-in experimental Claude cch signing#2473
feat: add opt-in experimental Claude cch signing#2473luispater merged 2 commits intorouter-for-me:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37249339ac
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if cloakMode == "" { | ||
| cloakMode = attrMode | ||
| strictMode = attrStrict | ||
| } | ||
| if len(sensitiveWords) == 0 { | ||
| sensitiveWords = attrWords |
There was a problem hiding this comment.
Preserve ClaudeKey strict/word settings when mode is omitted
When a claude-key has cloak with no mode (documented default auto), this branch now treats the empty mode as “use auth attributes” and unconditionally assigns strictMode = attrStrict and sensitiveWords = attrWords. In common deployments those auth attributes are absent, so configured strict-mode: true or sensitive-words from config.yaml are silently dropped unless mode is explicitly set, which regresses previous behavior that preserved configured strict/sensitive settings while only filling missing values.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Code Review
This pull request introduces an experimental feature for signing Claude /v1/messages request bodies using a CCH signing algorithm, which is disabled by default. The changes include adding the xxHash dependency, updating the configuration schema to include experimental-cch-signing, and implementing the signing logic within the Claude executor. Additionally, the PR refactors configuration resolution and adds comprehensive tests for the new signing behavior and zstd response decoding. Feedback was provided regarding an opportunity to optimize performance by reducing redundant configuration lookups during the request lifecycle.
| useExperimentalCCHSigning := experimentalCCHSigningEnabled(cfg, auth) | ||
|
|
||
| // Get cloak config from ClaudeKey configuration | ||
|
|
||
| cloakCfg := resolveClaudeKeyCloakConfig(cfg, auth) |
There was a problem hiding this comment.
There's an opportunity to improve efficiency here. The resolveClaudeKeyConfig function is called multiple times for a single request:
- Once via
experimentalCCHSigningEnabledinsideapplyCloaking. - Once via
resolveClaudeKeyCloakConfiginsideapplyCloaking. - Again via
experimentalCCHSigningEnabledin the calling functions (ExecuteandExecuteStream).
This results in iterating over the ClaudeKey configurations three times per request.
Consider resolving the ClaudeKey configuration once in Execute and ExecuteStream and then passing the resolved config down to applyCloaking. This would avoid the redundant lookups.
For example, you could modify Execute and ExecuteStream like this:
// In Execute() and ExecuteStream()
claudeKeyCfg := resolveClaudeKeyConfig(e.cfg, auth)
// ...
// Pass the resolved config to applyCloaking
body = applyCloaking(ctx, claudeKeyCfg, auth, body, baseModel, apiKey)
// ...
if claudeKeyCfg != nil && claudeKeyCfg.ExperimentalCCHSigning {
bodyForUpstream = signAnthropicMessagesBody(bodyForUpstream)
}And then update applyCloaking to accept *config.ClaudeKey instead of *config.Config and use it directly:
func applyCloaking(ctx context.Context, claudeKeyCfg *config.ClaudeKey, auth *cliproxyauth.Auth, payload []byte, model string, apiKey string) []byte {
var useExperimentalCCHSigning bool
var cloakCfg *config.CloakConfig
if claudeKeyCfg != nil {
useExperimentalCCHSigning = claudeKeyCfg.ExperimentalCCHSigning
cloakCfg = claudeKeyCfg.Cloak
}
// ... rest of the function using cloakCfg and useExperimentalCCHSigning
}There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15c2f274ea
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
|
|
||
| cch := fmt.Sprintf("%05x", xxHash64.Checksum(body, claudeCCHSeed)&0xFFFFF) | ||
| return claudeBillingHeaderPlaceholderPattern.ReplaceAll(body, []byte("${1}"+cch+"${3}")) |
There was a problem hiding this comment.
Restrict cch substitution to the injected system header
signAnthropicMessagesBody applies ReplaceAll over the entire serialized request body, so any user content that happens to contain a full x-anthropic-billing-header: ... cch=00000; string will also be rewritten. This mutates user prompts and can change model behavior in otherwise valid inputs; the replacement should be scoped to the injected billing header field (for example, system[0].text) rather than every regex match in raw JSON.
Useful? React with 👍 / 👎.
xkonjin
left a comment
There was a problem hiding this comment.
Review: Experimental Claude CCH Signing
This is a clean implementation of opt-in CCH signing for Claude Code compatibility. The feature flag approach is the right call for experimental features.
Strengths:
- Clean separation with new claude_signing.go file
- Excellent test coverage with the new test cases
- The xxHash64 implementation with the seed constant matches the documented algorithm
- Config opt-in prevents breaking existing deployments
Security considerations:
-
The regex pattern is anchored to
cch=00000- confirm this is always the placeholder value from generateBillingHeader() -
Potential bug: In generateBillingHeader(), when experimentalCCHSigning is true, you return early with
cch=00000;, but the signing happens after cloaking in applyCloaking(). The order matters - verify the hash is computed on the fully-final body.
Code quality:
- The resolveClaudeKeyConfig refactor is good - consolidates the lookup logic
- Consider adding a comment explaining the seed value origin
Test gap: No test for the streaming path (ExecuteStream) with CCH signing enabled - the logic is duplicated there and should be verified.
Approving with minor notes.
Summary
experimental-cch-signingClaude credential flag/v1/messagesbody with seeded xxHash64 only when the flag is enabledcch=00000is left untouchedMotivation
This makes it possible to experiment with a Claude Code-style
cchsigning path without turning it into a hard dependency for every Anthropic request.The safe default is deliberate: if Anthropic changes the seed or signing scheme, CLIProxyAPI continues to operate exactly as it does today unless an operator explicitly opts in.
Reference
Original implementation idea and reverse-engineering discussion:
Tests
go test ./internal/configgo test ./internal/runtime/executor -run 'TestClaudeExecutor_ExperimentalCCHSigning|TestCheckSystemInstructionsWithMode_|TestApplyClaudeHeaders_DisableDeviceProfileStabilization|TestClaudeExecutor_ReusesUserIDAcrossModelsWhenCacheEnabled|TestClaudeExecutor_ExecuteStream_AcceptEncodingOverrideCannotBypassIdentity|TestDecodeResponseBody_MagicByteZstdNoHeader'