All posts
security reflection

When the coding harness becomes a trust boundary

Article Writer
Article Writer · Marketing
July 6, 2026 · 6 min read

There are four ways to write an apostrophe that look identical on screen. The ASCII quote, the right single quotation mark, the modifier letter apostrophe, and the modifier letter prime. For about three months this year, the apostrophe in “Today’s date” inside Claude Code’s system prompt was not a stylistic choice. It was a payload. Which of the four characters appeared depended on whether the API endpoint the user had configured matched a list of China-linked domains, a list of Chinese AI-lab keywords, both, or neither.

Nobody outside Anthropic knew, because nobody reads a system prompt byte by byte. That is the part of the episode we keep coming back to.

What actually happened

The story has two acts, and the first one made the second one findable.

In late March, Anthropic shipped version 2.1.88 of the Claude Code npm package with a 59.8 MB JavaScript source map inside it. A packaging oversight, the build tool generated the map by default and nothing excluded it, and suddenly roughly 513,000 lines of unminified TypeScript were public. The package was fixed quickly, but the internals had been mirrored within hours, and from that point on the tool’s behavior was under much closer community scrutiny than a minified bundle normally gets.

The second act landed at the end of June. A developer analyzing the shipped packages found that, starting with version 2.1.91 in early April, Claude Code carried obfuscated logic that activated when a user pointed the tool at a non-default API endpoint via ANTHROPIC_BASE_URL. The code compared the endpoint’s hostname against an embedded list of 147 domains associated with Chinese companies, plus a keyword list referencing Chinese AI providers. The lists shipped encoded with base64 and a single-byte XOR, which hides them from a casual string search and from nothing else. The result of the comparison was written into the prompt through the apostrophe trick. A second signal rode alongside it: if the machine’s timezone was Asia/Shanghai or Asia/Urumqi, the date format in the prompt switched from YYYY-MM-DD to YYYY/MM/DD.

The plausible motive is not mysterious. Anthropic has publicly documented industrial-scale attempts by competing labs to distill its models through proxy infrastructure, and a routing fingerprint is one way to tag suspect traffic. Anthropic acknowledged the code after the reports and removed it in version 2.1.197, published the first day of July.

Worth stating precisely: the researcher did not capture live traffic, so what is established is that the marker existed in the prompt, not where every copy of it ended up. Users on the default endpoint were never fingerprinted. But anyone routing through a custom gateway had their prompt silently annotated with a claim about who they might be.

The harness was never a neutral pipe

We have written before about treating tool output as untrusted input, and about keeping authorization in the runtime rather than the prompt. Both of those practices assume a particular map of the territory: the model is the unpredictable part, the inputs are the hostile part, and the software that connects them is plumbing. This episode redraws the map. The plumbing has opinions.

A coding harness assembles the context. That is its whole job. It reads the environment, the working directory, the git state, the user’s configuration, and it composes the text the model actually sees. Which means it has read access to things the user never typed, the timezone, the hostname of the configured endpoint, and write access to every byte of the prompt. The system prompt that feels like a fixed, inspectable artifact is actually co-authored on every request, and one of the authors is a vendor’s build pipeline that updates itself weekly.

What the fingerprint demonstrated is that this write access supports covert channels. A prompt is an interface, and interfaces can carry side channels exactly the way network protocols can. Invisible Unicode is invisible to a person skimming logs. It is not invisible to a diff tool, a hexdump, or the party receiving the request, which is the point.

The asymmetry is what makes it a trust question rather than a technical one. The user cannot practically audit a minified 50 MB bundle on every release. It took an accidental source leak, then months, then a determined reverse engineer to surface four apostrophes. The harness sits inside the developer’s trust boundary, with shell access and credentials in scope, on the strength of a reputation, not an inspection.

A control that fails at its own job

Grant the motive entirely and the design still does not hold up. A distillation operation sophisticated enough to route traffic through proxy infrastructure is sophisticated enough to change a hostname and set a timezone. The signal is trivial for the actual target to strip. Meanwhile it fires on everyone else who uses a custom endpoint for ordinary reasons, corporate gateways, compliance proxies, cost routers, research infrastructure. The people tagged are disproportionately the people who were never the problem.

That trade might still be defensible as one weak signal among many. What is not defensible is the covertness. A documented “we annotate requests from custom endpoints for abuse detection” line in the changelog would have cost the mechanism little of its value against unsophisticated abuse and all of its scandal. The decision to hide it in homoglyphs is the decision that turned an anti-abuse measure into a trust incident.

What we do differently now

We have a particular stake in this. Our agents live inside harnesses like this one. Every run, the entire world our models perceive is a context assembled by software we did not write, and the lesson generalizes past one vendor.

So the harness is now on our dependency review list like any other package, not treated as part of the machine. We pin versions and take upgrades deliberately instead of riding latest. Where a prompt is a security surface, we compare byte for byte, because eyeballing rendered text is exactly the audit the apostrophe trick was designed to survive. And when we reason about what left the building in a request, we count the whole assembled context as the payload, not just the parts we authored.

None of that would have caught this quickly. That is worth being honest about. A single-byte homoglyph in a vendor prompt is beyond the review budget of a small team, and probably beyond most large ones. What changes is the posture: we no longer model the layer between us and the model as empty space.

The larger shift is in where the boundary gets drawn. For years the anxious question about AI tooling was what the model might do. The model, it turns out, was the legible part. It is the software that speaks to the model on our behalf, silently versioned, silently updated, holding the pen on every prompt, that has to be promoted to a first-class party in the threat model. We expect more episodes like this one, found the same way, by someone diffing bytes nobody was supposed to look at.