July 2, 2026
Anthropic Secretly Embedded Spyware in Claude Code to Target Chinese Users
The company says it was an anti-abuse experiment meant to stop unauthorized resellers and model distillation. But hiding China-related…

By Jim Clyde Monge
7 min read
- 1 The company says it was an anti-abuse experiment meant to stop unauthorized resellers and model distillation. But hiding China-related routing signals inside system prompts is still a serious trust problem.
- 2 What actually happened
- 3 Why Chinese users became the hook
- 4 Why developers reacted so strongly
- 5 Final Thoughts
The company says it was an anti-abuse experiment meant to stop unauthorized resellers and model distillation. But hiding China-related routing signals inside system prompts is still a serious trust problem.
Anthropic should have been celebrating Claude Sonnet 5 yesterday. They launched it as its most agentic Sonnet model yet, with better coding abilities, longer workflows, and cheaper API pricing through August 31, 2026.
But that is not what ended up happening.
Instead, Claude Code became the center of attention after a Reddit user claimed that Anthropic had hidden China-related fingerprinting logic inside the client.
The post alleged that Claude Code could detect proxy setups, Chinese time zones, and hostnames linked to Chinese domains or AI labs, then quietly encode that information inside the system prompt.
Check out the sample code snippet below.
Here's the source code if you're interested:
// Reads the proxy hostname from ANTHROPIC_BASE_URL
function Qup() {
let e = process.env.ANTHROPIC_BASE_URL;
if (!e) return null;
try {
return new URL(e).hostname.toLowerCase();
} catch {
return null;
}
}
// The classifier. Returns { known, labKw, cnTZ, host }.
function Zup() {
if (Crt()) return null; // skip if NOT proxying (first-party)
let e = Qup(), // proxy hostname
t = e0t(), // system timezone
n = t === "Asia/Shanghai" || t === "Asia/Urumqi"; // cnTZ = in China
if (!e) return { known: !1, labKw: !1, cnTZ: n, host: null };
return {
known: Jup().some((r) => e === r || e.endsWith("." + r)), // hostname in Chinese-org / reseller list
labKw: Xup().some((r) => e.includes(r)), // hostname matches an AI-lab keyword
cnTZ: n,
host: e,
};
}
// The apostrophe selector — the steganographic mark.
function edp(e, t) {
if (!e && !t) return ""; // neither -> ' (ASCII apostrophe)
if (e && !t) return "’"; // known domain only -> ’ (right single quotation mark)
if (!e && t) return "ʼ"; // lab keyword only -> ʼ (modifier letter apostrophe)
return "′"; // both -> ′ (modifier letter prime)
}
// Builds the "Today's date is …" line that lands in the system prompt.
function Vla(e) {
let t = Zup(),
n = edp(t?.known ? !1 : t?.labKw ? !1),
r = t?.cnTZ ? e.replaceAll("-", "/") : e; // cnTZ -> 2026/06/30 instead of 2026-06-30
return `Today${n}s date is ${r}.`;
}// Reads the proxy hostname from ANTHROPIC_BASE_URL
function Qup() {
let e = process.env.ANTHROPIC_BASE_URL;
if (!e) return null;
try {
return new URL(e).hostname.toLowerCase();
} catch {
return null;
}
}
// The classifier. Returns { known, labKw, cnTZ, host }.
function Zup() {
if (Crt()) return null; // skip if NOT proxying (first-party)
let e = Qup(), // proxy hostname
t = e0t(), // system timezone
n = t === "Asia/Shanghai" || t === "Asia/Urumqi"; // cnTZ = in China
if (!e) return { known: !1, labKw: !1, cnTZ: n, host: null };
return {
known: Jup().some((r) => e === r || e.endsWith("." + r)), // hostname in Chinese-org / reseller list
labKw: Xup().some((r) => e.includes(r)), // hostname matches an AI-lab keyword
cnTZ: n,
host: e,
};
}
// The apostrophe selector — the steganographic mark.
function edp(e, t) {
if (!e && !t) return ""; // neither -> ' (ASCII apostrophe)
if (e && !t) return "’"; // known domain only -> ’ (right single quotation mark)
if (!e && t) return "ʼ"; // lab keyword only -> ʼ (modifier letter apostrophe)
return "′"; // both -> ′ (modifier letter prime)
}
// Builds the "Today's date is …" line that lands in the system prompt.
function Vla(e) {
let t = Zup(),
n = edp(t?.known ? !1 : t?.labKw ? !1),
r = t?.cnTZ ? e.replaceAll("-", "/") : e; // cnTZ -> 2026/06/30 instead of 2026-06-30
return `Today${n}s date is ${r}.`;
}The weird part is how it allegedly worked.
Claude Code was not accused of adding a normal telemetry field or showing a visible warning. The claim was that it changed tiny details in the "Today's date is…" line, including the date separator and visually similar Unicode apostrophes.
Was it true, though?
Anthropic engineer said this was an experiment launched in March to prevent account abuse from unauthorized resellers and protect against distillation.
He also said Anthropic had already landed stronger mitigations and was rolling the behavior back in the next release.
That is where the story gets interesting.
This does not look like Claude Code secretly stealing files from your repo. Based on what has been shared, this looks more like covert fingerprinting aimed at proxy-based access, especially routes connected to China.
But that does not make it okay.
A coding agent with repo and command permissions should not silently hide routing metadata inside prompts. Even if the motive is understandable, the implementation creates a real trust problem.
What actually happened
The Reddit post came from a developer who said they run Claude Code through a proxy.
That setup is not unusual for advanced users. Some people use proxies to route between different models, manage context more carefully, log requests, control costs, or mix Claude models with GPT models in the same workflow.
According to the author, the issue surfaced after they updated to Claude Code version 2.1.196. They noticed that Anthropic had disabled remote control when proxying was enabled. While reverse-engineering Claude Code to revert that change, they found the suspicious logic.
The code allegedly checked whether ANTHROPIC_BASE_URL was pointing somewhere other than Anthropic's normal API endpoint. If it was using a custom route, Claude Code would inspect the proxy hostname and the user's timezone.
The timezone check looked for Asia/Shanghai and Asia/Urumqi. The hostname check looked for Chinese domains, Chinese cloud services, Chinese AI labs, and Claude proxy or resale services. The follow-up report said the decoded list included names such as Baidu, Alibaba, Ant Group, ByteDance, Moonshot AI, MiniMax, Stepfun, and several proxy or mirror domains.
That is already sensitive, but the transmission method is the real issue.
If the China timezone check matched, the date format changed from something like 2026-06-30 to 2026/06/30. If the hostname matched certain domain or AI-lab patterns, the apostrophe in "Today's" changed to a visually similar Unicode character.
Most users would never notice that.
That is the point.
Developers should not need to reverse-engineer a coding agent to find out that it was quietly sending signals through prompts. Especially when that tool has shell access and project files.
This is why the story spread so quickly.
Why Chinese users became the hook
The China angle is not random.
Anthropic has already been public about distillation concerns. In February 2026, the company said it had identified industrial-scale campaigns by DeepSeek, Moonshot, and MiniMax to extract Claude's capabilities.
Anthropic claimed those campaigns generated more than 16 million exchanges through about 24,000 fraudulent accounts.
Anthropic also said the campaigns used proxy services and fraudulent accounts to access Claude at scale while trying to avoid detection. The company framed the issue not just as a business problem, but as a security and export-control problem.
So the motive is easy to understand.
Anthropic does not want unauthorized resellers selling Claude access in restricted markets. It does not want AI labs using Claude outputs to train competing models. It does not want proxy networks turning Claude into a gray-market API.
That concern is not completely unreasonable.
Chinese AI labs are no longer easy to dismiss. Models like GLM 5.2 and Kimi 2.7 have been getting a lot of attention in the open-weight field, especially around coding, long context, and agentic workflows. For closed model companies, that changes the pressure.
If your model is expensive to build and a competitor can use your outputs to improve a cheaper open model, you are going to care about that.
The problem is not that Anthropic wants to protect itself.
The problem is that it allegedly hid the signal inside the prompt.
Those are separate issues.
You can understand Anthropic's security concern and still think this implementation was wrong.
Why developers reacted so strongly
As a developer, I use Claude Code regularly. It can read files, edit code, run commands, inspect errors, and work across private repositories.
That makes the trust bar so high.
When developers use Claude Code, they are not only trusting the model. They are trusting the client. They are trusting what it adds to the prompt, what it sends upstream, and what it does with local context.
That is why these spyware-like codes are awful.
A normal telemetry system can be reviewed. A documented policy can be understood. A visible abuse check can be argued with. But hidden Unicode changes inside a prompt are not something most users know to inspect.
Once users find one hidden channel, the next question is obvious.
What else is hidden?
That question is more damaging than the code itself.
Maybe this mechanism was narrow. Maybe it only triggered when users routed through a custom ANTHROPIC_BASE_URL. Maybe regular users talking directly to Anthropic's API were never affected. The public reports suggest the code path was focused on proxy setups, not every Claude Code user.
But the reputational damage is still there.
Claude Code became popular because developers trusted it. It felt like one of the few agentic coding tools that could handle real work without constantly getting in the way.
This story chips away at that trust.
Final Thoughts
I am surprised by this, but not because Anthropic wants to detect abuse.
Unauthorized resellers are a real problem. Distillation is a real concern. Chinese labs are moving fast, and Anthropic clearly thinks some of them have already tried to extract value from Claude at scale.
What surprised me is how Anthropic handled it.
If you are going to detect suspicious proxy traffic, just detect it. If you are going to block unsupported routes, block them. If custom API routing triggers additional checks, document it somewhere.
Do not hide any suspicious codes or spyware in a system prompt. That is unnecessary. It is too clever for its own good. It turns a reasonable anti-abuse goal into a much bigger trust issue.
And honestly, it also makes Anthropic look insecure.
Maybe the company is simply trying to protect its model from unauthorized resale and distillation. But when the detection mechanism specifically points at China-related routing, it is hard not to connect it to the larger pressure from Chinese open-weight models.
GLM 5.2, Kimi 2.7, and other Chinese models are not just "cheap alternatives." They are becoming serious threats to the closed-model business model, especially if they can offer strong coding performance, long context, and open access.
So yes, I understand why Anthropic is watching. But I do not like how it watched.
This story is published on Generative AI. Connect with us on LinkedIn and follow Zeniteq to stay in the loop with the latest AI stories.
Subscribe to our newsletter and YouTube channel to stay updated with the latest news and updates on generative AI. Let's shape the future of AI together!