xAI's Grok CLI Uploaded a File It Was Explicitly Told Not to Read

A researcher planted a file called never_read_canary.txt, told xAI's Grok Build CLI never to open it, and got back a one-word reply: OK. The file showed up anyway, synced whole with the project's entire git history to a Google Cloud Storage bucket named grok-code-session-traces.

In brief

On a 12-gigabyte test repository, xAI's coding CLI quietly uploaded 5.1 gigabytes as a background git bundle, against 192 kilobytes that actually passed through the chat with the model — a 27,800-to-1 gap the researcher used as proof the whole repo goes up, read or not.

Turning off the CLI's own "Improve the model" setting changed nothing; the server kept reporting uploads as enabled. In the thread, one developer dropped Grok Build over it, others started sandboxing every coding agent behind their own network proxies.

Watching the wire: what actually leaves the laptop

A developer publishing as cereblab set out to answer one question with evidence instead of a terms-of-service reading: what does xAI's Grok Build CLI send home while it works on your code? The method was network interception, not speculation: mitmproxy installed, its certificate trusted in the system keychain, all of Grok's traffic routed through it, and the decrypted request bodies read straight off the wire.

Two channels did almost all the work, and they behave very differently:

Channel Endpoint What travels Tied to what's read?
Chat turns POST cli-chat-proxy.grok.com/v1/responses Contents of files the agent opens, verbatim, including a .env secrets file when one exists Yes
Codebase snapshot POST cli-chat-proxy.grok.com/v1/storage + direct storage.googleapis.com PUTs The entire tracked repository plus full git history, as a git bundle, into a bucket named grok-code-session-traces No, uploaded regardless
Telemetry Mixpanel and xAI event tracking Usage events No

The scale gap is the tell. On the 12 GB test repository, the storage channel pushed 5.10 GiB in 73 chunks of roughly 75 MB each, every one returning HTTP 200. The chat channel, across the same session, moved 192 KB. That 27,800-to-1 ratio is the researcher's central evidence that the upload is a repository mirror running on its own schedule, not a byproduct of the agent reasoning about your code.

The file Grok was told never to open

To settle it beyond doubt, the researcher planted src/_probe/never_read_canary.txt, a file with a unique marker string, and gave the CLI one instruction: "Reply with exactly: OK. Do not read or open any files." Grok replied OK. The storage endpoint still returned 200 on a fresh git bundle. Cloning that bundle recovered the canary file, marker intact, along with the project's complete commit history, which the agent had no reason to fetch for a one-word reply.

The control users would reasonably expect to matter doesn't. Switching "Improve the model" off left the CLI's own /v1/settings response unchanged: trace_upload_enabled: true, upload_enabled: true. The repository upload continued exactly as before. The author is careful about the boundary of the claim: "Upload/storage ≠ training. That is governed by policy and account tier; we measured transmission only." What's proven is that the data leaves the machine and xAI's servers accept it, not that it trains anything.

There is a real off switch, just not the one in the settings menu: an environment variable, GROK_TELEMETRY_TRACE_UPLOAD=0, and a config flag, \~/.grok/config.toml → [harness] disable_codebase_upload = true, both absent from the product's own UI.

A reader turned Grok's own CLI against itself

The HN thread didn't just react: some of it independently pressure-tested the finding. One commenter pointed the CLI at its own binary:

"just for chuckles, i asked grok cli to check disclosure and look through the binary and logs to see which config would stop it from doing that. no idea if it truly works, but here it is" — a developer who turned Grok's own CLI against itself to hunt for the kill switch

What came back matched the gist's own config flag almost line for line, plus two more:

[harness]
disable_codebase_upload = true

[telemetry]
trace_upload = false

[features]
telemetry = false

Not everyone treated the report as settled fact, though. One reader said he'd want a human-verified reproduction before trusting a write-up that reads as AI-drafted, and another guessed it was exactly that: an agent's own audit pasted into a gist. Nobody in the thread produced an independent mitmproxy capture of their own to close that gap.

Developers were already sandboxing coding agents before this

What wasn't in doubt was the appetite for a fix that doesn't wait on xAI. One developer described the setup he already runs for every coding tool, not just Grok's:

"I always separate the coding tools from LLM providers, and use bubblewrap to sandbox the coding tools … they can only access the internet through an HTTP proxy hosted on a Unix socket, can only access specific LLM provider hostnames, and exclude the tool's own hostname" — a developer who sandboxes every coding agent with bubblewrap, routing its network through a Unix-socket proxy that allow-lists only the model API

Another had gone further and built the plumbing himself:

"I recently bolstered my own personal CLIProxyAPI fork to use an algo similar to gitleaks/betterleaks to, on the fly, scan the incoming … stream for any secrets that may have been transmitted from disk, replace them with a unique identifier, send that off to the upstream provider, and then replace the secret … before sending any response back" — a developer who built his own proxy to scrub secrets from every file before it reaches the model provider

Neither treats it as a Grok-specific problem. One argued that any proprietary agent runner, Claude Code and Codex included, carries the same risk by design, and that routing model calls through an open harness like OpenCode is the only way to know what's actually being sent. On the adoption side, the reaction was blunter: a developer who'd been weighing Grok-4.5 against other coding models on price and capability alone said the upload behavior tipped the decision: competitive pricing and a model good enough to use, undone by not knowing what leaves the laptop.

Get breakdowns like this every day

The top Hacker News stories, unpacked — by email, Telegram, or RSS.

Next story · 6 of 30 Read more
🚀Tech

A JS runtime's 'built from scratch' claim ran into a months-old GitHub issue

theMackabu's Show HN for Ant, a JavaScript runtime bundled with its own package registry, sandboxing and desktop layer, climbed to 301 points within a day. In the thread, engineers ran the site's 'near-V8 speeds' line against an outside benchmark project, and one commenter traced the 'hand-built from scratch' engine back to a GitHub issue about an existing AGPL codebase.

★ 301 · 💬 133 · antjs.org · 5 min