Claude Code Is Steganographically Marking Requests

kirushik1 pts0 comments

Claude Code Is Steganographically Marking Requests<br>Back to all blogs#security<br>#reverse-engineering<br>#ai<br>#privacy

June 30, 2026<br>6 min read

A blog post by<br>Claude Code Is Steganographically Marking Requests

I inspected Claude Code for privacy reasons and found hidden system prompt markers based on API base URL and timezone.

I was inspecting Claude Code for privacy reasons.<br>Most devs give their harnesses ridiculous access. FS, shell, git, browser access, even computer use nowadays. That is the whole point. They need enough context to do useful work.<br>That also means the client itself deserves scrutiny. If a coding agent can read your repo and run commands, the binary that ships it should be boring (ƒor example, pi harness)<br>So I took a look at my local Claude Code (2.1.196) install.<br>Marker<br>Inside the Claude Code binary, there is a function that changes the current date string inserted into the system prompt.<br>The normal string looks like this:<br>text<br>Copy<br>Today's date is 2026-06-30.

Claude Code can silently change two things:<br>The apostrophe in Today's<br>The date separator, from - to /<br>Here is the relevant code, cleaned up from the minified bundle:<br>js<br>Copy<br>function Zup() {<br>if (Crt()) return null;

let host = Qup();<br>let timezone = e0t();<br>let cnTZ = timezone === "Asia/Shanghai" || timezone === "Asia/Urumqi";

if (!host) {<br>return {<br>known: false,<br>labKw: false,<br>cnTZ,<br>host: null,<br>};

return {<br>known: Jup().some((domain) => host === domain || host.endsWith("." + domain)),<br>labKw: Xup().some((keyword) => host.includes(keyword)),<br>cnTZ,<br>host,<br>};

function edp(known, labKw) {<br>if (!known && !labKw) return "'";<br>if (known && !labKw) return "\u2019";<br>if (!known && labKw) return "\u02BC";<br>return "\u02B9";

function Vla(date) {<br>let marker = Zup();<br>let apostrophe = edp(marker?.known ?? false, marker?.labKw ?? false);<br>let renderedDate = marker?.cnTZ ? date.replaceAll("-", "/") : date;

return `Today${apostrophe}s date is ${renderedDate}.`;

This is prompt steganography, a technique used to hide data in plain sight.<br>The visible sentence still reads like a normal date. The model and the user see something boring. The raw request contains a marker.<br>Checks<br>js<br>Copy<br>function Crt() {<br>let baseUrl = process.env.ANTHROPIC_BASE_URL;<br>if (!baseUrl) return true;<br>return Rrt(baseUrl);

function Rrt(baseUrl) {<br>try {<br>let host = new URL(baseUrl).host;<br>return ["api.anthropic.com"].includes(host);<br>} catch {<br>return false;

function Qup() {<br>let baseUrl = process.env.ANTHROPIC_BASE_URL;<br>if (!baseUrl) return null;

try {<br>return new URL(baseUrl).hostname.toLowerCase();<br>} catch {<br>return null;

The trigger is ANTHROPIC_BASE_URL, Claude Code's API base URL override.<br>Then it checks if:<br>the system timezone is Asia/Shanghai or Asia/Urumqi<br>the API base URL hostname matches a decoded domain list<br>the hostname contains specific AI lab keywords<br>The timezone check changes:<br>text<br>Copy<br>2026-06-30

into:<br>text<br>Copy<br>2026/06/30

The hostname check changes the apostrophe:<br>ConditionApostropheNormal'Known domain\u2019Lab keyword\u02BCKnown domain and lab keyword\u02B9<br>These are visually tiny changes you would never notice in most mono fonts.<br>Obfuscated List<br>The domain and keyword lists are stored as base64 strings and XOR-decoded with key 91.<br>js<br>Copy<br>var Kup = 91;

function Gla(encoded) {<br>let bytes = Buffer.from(encoded, "base64");<br>let out = "";

for (let byte of bytes) {<br>out += String.fromCharCode(byte ^ Kup);

return out.split(",");

The decoded lab keyword list is:<br>text<br>Copy<br>deepseek,moonshot,minimax,xaminim,zhipu,bigmodel,baichuan,stepfun,01ai,dashscope,volces

The decoded domain list is much larger. It contains Chinese corporate domains, AI company domains, and a lot of proxy / reseller / gateway domains.<br>Some examples:<br>text<br>Copy<br>cn<br>baidu.com<br>alibaba-inc.com<br>alipay.com<br>antgroup-inc.cn<br>bytedance.net<br>kuaishou.com<br>xiaohongshu.com<br>jd.com<br>bilibili.co<br>iflytek.com<br>stepfun-inc.com<br>moonshot.ai<br>anyrouter.top<br>claude-code-hub.app<br>claude-opus.top<br>openclaude.me<br>proxyai.com<br>yunwu.ai<br>zenmux.ai

You can view the full list here: https://cdn.thereallo.dev/blog/assets/cc-domains.js<br>How It's Passed<br>The date function is used when building the agent context:<br>js<br>Copy<br>...userEmail && {<br>userEmail: `The user's email address is ${userEmail}.`<br>},<br>...attachedProject && {<br>attachedProject<br>},<br>currentDate: Vla(GSe())

So the marker becomes part of the system context sent to the model. (Where Anthropic probably parses in their backend)<br>What Mine Shows<br>My installed binary is signed by Anthropic:<br>text<br>Copy<br>Identifier=com.anthropic.claude-code<br>TeamIdentifier=Q6L2SF6YDW<br>Timestamp=Jun 29, 2026<br>SHA256=6fc6e61ab7582c2bf241225ff90d9f79e91d69380cb9589fc9dedd3a30070f5a

My current shell had ANTHROPIC_BASE_URL unset, and my timezone was:<br>text<br>Copy<br>Asia/Hong_Kong

So on my machine, under my current environment, this path would produce the normal apostrophe and the normal YYYY-MM-DD date string.<br>Concerning<br>Anthropic probably wants to detect API resellers, unauthorized Claude Code gateways, and model "distillation attack"...

return claude code copy date host

Related Articles