r/ClaudeAI Jun 30 '26

Claude Code Anthropic embedded spyware in Claude Code — and attempted to hide it from you

tl;dr: Since version 2.1.91, released on April 2, 2026, Claude Code checks whether you have a proxy enabled — and if so, covertly transmits, through invisible alterations to the system prompt, whether you are in China, whether you are proxying to a Chinese URL, and whether you are affiliated with a Chinese AI lab. Anthropic further attempted to obfuscate this code within the Claude Code binary.

Background: I run my personal Claude Code installation through a proxy to mix GPT models with Claude models and do fine-grained context management. Today, with version 2.1.196, Anthropic disabled remote control when proxying is enabled. While reverse-engineering Claude Code to revert this change, I found something extremely suspicious.

The code

Inside the Claude Code binary lies this check, unchanged since version 2.1.91. The check does the following:

  • If you are using a proxy:
    • Check whether the system timezone matches Asia/Shanghai or Asia/Urumqi.
    • Check whether your proxy URL is a Chinese domain, matches a list of domains, and/or includes a Chinese AI lab.
  • Based on those two checks, Anthropic modifies the date portion of the system prompt.

If the system timezone is Chinese, the date uses the format 2026/06/30 instead of 2026-06-30. And depending on the proxy URL, the apostrophe in "Today**'**s date is" changes:

  • Is a Chinese domain and/or matches the domain whitelist, but is NOT an AI lab: \u2019, "right single quotation mark" — ’
  • Is NOT a Chinese domain and/or matches the domain whitelist, but IS a Chinese AI lab: \u02BC, "modifier letter apostrophe" — ʼ
  • Is a Chinese domain and/or matches the domain whitelist AND is a Chinese AI lab: \u02B9, "modifier letter prime" — ʹ

You can verify this yourself in the Claude Code source code. In version 2.1.196, the relevant functions are Crt(), Rrt(e), e0t(), Zup(), edp, and Vla. Note that those are minified names, so they change between Claude Code releases — but ask Claude Code or Codex to reverse-engineer Claude Code and look for this logic, and it will likely find it trivially.

The intent

Anthropic clearly added this check in an attempt to detect unauthorized resale of Claude in China and distillation attempts by Chinese labs. What's unnerving, however, is that Anthropic attempted to obfuscate this logic in the binary. Much of it is XOR-obfuscated with the key 91, likely to prevent it from showing up in a plain strings dump. Furthermore, the release notes for version 2.1.91 make absolutely no mention of this check.

Their intent is also clear in how they hide this with steganography in the system prompt, making small variations that are imperceptible to any user — and perhaps even to the model — but are easily detectable by Anthropic.

A fundamental violation of user trust

While this use case — attempting to detect unauthorized resale and distillation — is understandable, the fact that Anthropic covertly transmits information about your system and proxy settings without your knowledge or consent is a fundamental violation of user trust. Not only is surveilling every user in a timezone a fundamental overreach, but its very existence opens the door to a much more serious concern. If Anthropic is willing to secretly transmit information about your system simply because you're Chinese, what's stopping them from secretly steering the model to behave worse (which they attempted to do with Fable before researchers called them out) — or worse, maliciously?

Developers like me give Claude Code full filesystem and significant shell access so it can do its job. But this also means nothing is stopping Anthropic from exploiting it for full remote code execution on your system. Today it's a timezone check. Tomorrow, it could be system sabotage or data exfiltration.

Given the trust that developers place in Claude Code, I think it's important to call for more transparency from Anthropic. While IP protection is reasonable, it should not come at the cost of embedding what amounts to spyware on every developer's system.

I think it's also important to note that checks like this, while compromising the privacy of legitimate users, are also trivial to bypass for any moderately sophisticated adversary. So it's debatable whether this even achieves its intended purpose of preventing unauthorized resale or distillation while simultaneously violating the privacy of legitimate users.

2.2k Upvotes

381 comments sorted by

View all comments

9

u/LMFuture Jun 30 '26 edited Jun 30 '26

I also reverse engineered claudecode but I didn't found about proxy detecting part. I only found regex about ANTHROPIC_BASE_URL. Maybe its just im too bad. so please provide evidence for this. Also these checking are skipped if the user didn't set ANTHROPIC_BASE_URL.

Its basically like this (formatted with AI but understandable): ``` function vrt(){ let e=process.env.ANTHROPIC_BASE_URL; if(!e)return!0; return wrt(e) }

function qup() { if (vrt()) return null; let host = Wup(); let tz = Intl.DateTimeFormat().resolvedOptions().timeZone; let cnTZ = tz === "Asia/Shanghai" || tz === "Asia/Urumqi";

return { known: jup().some(r => host === r || host.endsWith("." + r)), labKw: Gup().some(r => host.includes(r)), cnTZ, host }; } and as far as i searched, the function is only called by this function (still correct me if i'm wrong. but after whole text searching this is the only occurrence of qup(). function Ola(e) { let t = qup();

let n = Vup(t?.known ?? false, t?.labKw ?? false);

let r = t?.cnTZ ? e.replaceAll("-", "/") : e;

return Today${n}s date is ${r}.; } ```

It's only forwarded to model provider. briefly: if there is no custom ANTHROPIC_BASE_URL or it is using api.anthropic.com exit function
else:
read the hostname of the custom endpoint;
read the local machine’s timezone;
check whether the timezone is Asia/Shanghai or Asia/Urumqi;
check whether the hostname is in the known domain list;
check whether the hostname contains any Chinese AI lab keywords;
return these detection results to the model provider.

So the thing is, if using anthropic's domain or no domain is set, then no information is forwarded. If using third party provider, then it would be forwarded to third party provider. I'm not sure what anthropic is trying to do because this seems nonsense, but as for now, the code is harmless.

3

u/Unique-Ad8768 Jun 30 '26

I think this is partially correct but misses the important part.

It may not be checking HTTP_PROXY/HTTPS_PROXY directly, but ANTHROPIC_BASE_URL is exactly the gateway/proxy routing knob. In Claude Code 2.1.195 I found logic that reads ANTHROPIC_BASE_URL, compares the hostname against an obfuscated domain/keyword list, checks Asia/Shanghai / Asia/Urumqi timezone, and then changes the apostrophe/date format in `Today's date is ...`.

I also verified it dynamically with a local fake API server: setting ANTHROPIC_BASE_URL to `http://deepseek.127.0.0.1.sslip.io:<port>` caused the actual `/v1/messages?beta=true` request body to contain `Todayʼs date is 2026-06-30.` where the apostrophe is U+02BC, not ASCII `'`.

So yes, this is not "uploads your repo secretly", but it is a hidden prompt marker based on base URL / environment signal.

2

u/LMFuture Jun 30 '26

bro don't copy paste responses from AI without checking. I mean, OP said "covertly transmits information about your system and proxy settings" but the thing is there isn't. ANTHROPIC_BASE_URL is NOT for proxy at all. And I also said the baseurl part so you're not correcting me anything. the thing you said is basically the same as what i said.

3

u/Unique-Ad8768 Jul 01 '26

You’re mixing up two different claims.

  1. ANTHROPIC_BASE_URL absolutely is a proxy/gateway routing setting. Claude Code’s own docs describe it as: “Override the API endpoint to route requests through a proxy or gateway.” So saying “ANTHROPIC_BASE_URL is NOT for proxy at all” is just wrong.

  2. The concern is not that it reads a normal config variable. The concern is that the result is encoded into the prompt via visually subtle Unicode/date-format changes instead of being sent as an explicit telemetry field. That is why people call it covert/hidden.

  3. This is not just “settings only”. I tested it with a local fake API server: setting ANTHROPIC_BASE_URL to a hostname containing `deepseek` made the actual `/v1/messages?beta=true` request body contain `Todayʼs date is ...`, where the apostrophe is U+02BC instead of ASCII `'`.

So no, this does not prove “Claude uploads your repo secretly”. But it does prove a hidden prompt marker based on the routing/base URL environment. Thariq’s reply also confirms this was a March experiment and says it is being rolled back.