Someone posted on Reddit: Claude Code hides something unusual in its requests to the Anthropic API.

It’s not a regular system prompt. It’s a special field buried at the very start of the system array. It looks like this:

{
  "type": "text",
  "text": "x-anthropic-billing-header: cc_version=2.1.37.fbe; cc_entrypoint=cli; cch=a112b;"
}

Three fields: cc_version with a version number plus a mysterious suffix, cc_entrypoint hardcoded to cli, and cch — five hexadecimal characters that change with every single request.

What is this thing? How is it generated? Why all this complexity?

Someone decided to find out.


Starting from a Black Box

Claude Code shipped as a Bun binary. JavaScript bundled into a single executable, no node_modules, no source code — just compiled bytecode.

The researchers used three approaches:

First: MITM interception. Set up a proxy with mitmproxy to see what the actual outgoing requests looked like.

Second: Binary extraction. Bun embeds JavaScript source into the executable. Theoretically extractable, but what you get is a 2MB minified blob with single-letter variable names.

Third: Runtime debugging. Attach LLDB to the process, set memory watchpoints, and wait for the exact moment the hash gets written.

In practice, all three methods were used together.


First Discovery: The cch=00000 Placeholder in JavaScript

Searching the minified source for cch does find the billing header construction logic. But the code looks like this:

function u7R(T) {
  let R = `${VERSION}.${T}`;
  let A = process.env.CLAUDE_CODE_ENTRYPOINT ?? "unknown";
  return `x-anthropic-billing-header: cc_version=${R}; cc_entrypoint=${A}; cch=00000;`;
}

cch=00000, always. It’s a placeholder, and JavaScript doesn’t fill it in.

The real question: who does?


The Secret Lives in Zig Code

Claude Code uses a custom build of Bun: 1.3.9-canary.51+d5628db23. This commit doesn’t exist in the public oven-sh/bun repository.

Anthropic acquired Oven, the company behind Bun. So they have the ability to modify the runtime at a native level.

The custom Bun has a native fetch implementation written in Zig. When Claude Code makes a request, it doesn’t go through standard JavaScript fetch — it uses this custom native version.

This native fetch does three things:

  • Checks if the URL path contains /v1/messages
  • Checks for the anthropic-version header
  • Checks if the request body still has the cch=00000 placeholder

Only when all three conditions are met does it act.

It takes the entire request body (with the 00000 placeholder still in place), computes an xxHash64 hash, takes the lower 20 bits, converts to 5 hex characters, and overwrites those five zeros in place.

The whole thing happens in C-level memory. JavaScript can’t see it at all.


xxHash64: The Fast Hash Algorithm

Finding the algorithm took some tricks. Since there were no clues in the JavaScript code, the researchers looked at memory instead.

They attached LLDB to the cch=00000 memory region, triggered a request, and caught the watchpoint firing. The backtrace led to ___lldb_unnamed_symbol18111 at address 0x1015d05bc.

No symbols. No debug info. Just raw machine code.

Disassembling revealed five prime constants: 0x9E3779B185EBCA87, 0xC2B2AE3D27D4EB4F, and the rest, plus a standard avalanche finalization sequence.

This was textbook xxHash64, inlined directly into the binary with no external library calls.

The seed was sitting at 0x103e900e0 in the binary’s data section — a 64-bit constant, one of four stored together.

xxHash64 algorithm illustration: five prime constants surrounding a hash crystal

The researchers tested all four seeds against 142 input/output pairs they’d collected. Every single one matched.


The cc_version Suffix: Computed from Conversation Content

The cch is computed in native code, but the cc_version suffix comes from JavaScript.

The rule: take the first user message in the conversation, extract characters at positions 4, 7, and 20. If the message is too short, pad with zeros. Concatenate salt + picked chars + version, run through SHA-256, take the first 3 hex characters.

chars = "".join(msg[i] if i < len(msg) else "0" for i in (4, 7, 20))
suffix = sha256(f"{salt}{chars}{version}".encode()).hexdigest()[:3]

So for the same version number, the suffix changes with conversation content. That’s why cc_version is different every time.


What the xxHash64 Hash Protects

The research team ran systematic validation experiments. They captured real requests and modified them:

ModificationResult
Exact replay (no changes)200 OK
Modify system prompt (non-billing part)200 OK
Swap session UUID400 Rejected
Remove one tool400 Rejected
Change one word in a tool description400 Rejected
Add one MCP tool400 Rejected
Empty tools array400 Rejected

The conclusion is clear: the hash covers the entire serialized request body. messages, tools, metadata, model config, thinking config — all of it.

The only thing you can safely modify after the hash is computed is the non-billing part of the system prompt, because that’s injected into the system array after the hash placeholder is inserted.


Not DRM, It’s Billing

The name cch already gives it away. This is a “billing header” — for attribution and metering on Anthropic’s servers.

The choice of xxHash64 (a non-cryptographic hash) tells you something. It’s fast, not secure. The design philosophy is obfuscation, not encryption.

Using xxHash64 means this isn’t access control. If they really wanted to prevent abuse, they’d use HMAC or some symmetric/asymmetric signature. The researchers’ tests showed:

  • Not TLS fingerprinting
  • No binary attestation
  • No handshake sequence
  • No replay detection (same body can be sent multiple times)
  • No special UUID format checking

As long as the hash matches, the server accepts it.

This is fundamentally a moat to prevent unauthorized clients from freeloading on specific features (like fast mode) — not a security boundary.


Why This Discovery Matters

With this information, any third-party tool can implement the signing logic itself. No Bun binary needed, no reverse engineering required.

About 30 lines of code:

import hashlib, json, uuid, xxhash

# Get OAuth token from macOS Keychain
creds = json.loads(subprocess.check_output([
    "security", "find-generic-password",
    "-a", os.environ["USER"], "-s", "Claude Code-credentials", "-w"
], text=True).strip())
token = creds["claudeAiOauth"]["accessToken"]

# Compute version suffix
chars = "".join(prompt[i] if i < len(prompt) else "0" for i in (4, 7, 20))
suffix = hashlib.sha256(f"{salt}{chars}{version}".encode()).hexdigest()[:3]

# Build body with placeholder
body = json.dumps({...}, separators=(",", ":"))

# Compute cch
cch = format(xxhash.xxh64(body.encode(), seed=SEED).intdigest() & 0xFFFFF, "05x")
body = body.replace("cch=00000", f"cch={cch}")

# Send request

Request signing flow: JS construction → Zig validation → Server verification

The trickiest part is getting the JSON key order right. The placeholder sits in the system field, but if your JSON library puts messages before system — and the conversation content happens to contain the string cch=00000 — the replacement hits the wrong spot.

Solution: make sure your JSON serializer outputs system before messages. Also pad the hash to exactly 5 characters — a 4-character hash like 651f won’t match the 5-character placeholder 0651f.


A Side Note: Bun Native Fetch’s String Mutation

Here’s an interesting detail. Bun’s native fetch mutates JavaScript strings in place. After fetch() returns, the bytes in your body variable are already different.

JavaScript strings are supposed to be immutable per spec. This is a spec violation.

Worse, JavaScriptCore (JSC, the engine Bun uses) shares string backing stores across references. If you write const alias = body, both variables point to the same memory. After fetch(), both get mutated.

Map and Set keys, interned strings, rope substrings — all have this problem. Any code that happens to have cch=00000 in a runtime string, then sends a fetch to /v1/messages — even to a completely different server — will get silently rewritten.


What We Can Learn: Code Obscurity as a Design Philosophy

The biggest takeaway isn’t what Anthropic did — it’s how they did it.

The design decision to embed the hash in native runtime is interesting. There’s zero trace on the JavaScript side. You can’t find this function by tracing JS call stacks, can’t intercept it by hooking JS functions. The placeholder goes in as 00000 and comes out as a112b — looks like magic from JavaScript’s perspective.

The design philosophy: not making the door unopenable, but hiding the door so nobody knows where it is.

For developers who want deep integration with the Anthropic API, knowing these details helps understand the boundaries — what’s mutable and what’s not. For everyone else, it’s a good case study in what commercial software hides from plain sight.


FAQ

Q: Is this signing mechanism Anthropic’s official API?

No. This is Claude Code client implementation detail, not part of Anthropic’s public API specification. The official API documentation doesn’t mention the x-anthropic-billing-header field.

Q: Can I use Claude Code features without paying with this discovery?

No. The cch hash is a metering and attribution mechanism, not access control. The server uses it to identify legitimate Claude Code client traffic and meter it. It doesn’t affect API usage billing itself.

Q: Can this mechanism be blocked or changed?

Yes. Anthropic can change the algorithm or seed at any time, and every Claude Code update swaps out the constants. Extracting seeds from JavaScript requires binary analysis — difficult to automate, but not impossible.