← Back to Blog
July 13, 2026 7 min read

The Grok coding CLI sends your .env and entire repo to xAI. Disabling telemetry does not stop it.

xAI shipped a coding CLI called Grok Build a few months ago. You install it with a curl pipe, log in through a browser, and it edits your codebase using Grok 4.5. It joined a crowded field of AI coding agents, and I filed it under "another option" until a wire-level teardown cropped up on Hacker News this week with 454 points and 169 comments. The findings are specific, reproduced, and worth knowing about before you run Grok Build anywhere near production code.

An independent security researcher set up a mitmproxy between the Grok Build binary and xAI's servers, planted canary secrets in test repositories, and watched the actual bytes leave the machine. Three findings stood out. All three reproducible.

What Grok Build (v0.2.93) does by default
Model turns (POST /v1/responses)tagged .env sent verbatim
Session archive (POST /v1/storage)secrets file contents accepted (HTTP 200)
Whole-repo snapshotentire workspace uploaded as git bundle
Destinationgs://grok-code-session-traces
Captured on a standard consumer login. No special permissions, no API key. Both channels returned HTTP 200.

The .env travels unredacted

This is the part that should make anyone with production credentials in a repo sit up. The researcher created a canary .env file containing API_KEY=CANARY7F3A9-SECRET-should-not-leave and DB_PASSWORD=CANARY7F3A9-DBPASS. They asked Grok Build to read it as part of a coding task.

The values appeared in the captured request body to cli-chat-proxy.grok.com/v1/responses, the model-turn endpoint. They also appeared in a session_state archive headed to a second endpoint, POST /v1/storage, which accepted the upload with a 200 response. No redaction, no masking, no "[REDACTED]" placeholder. The secret is treated as ordinary file content.

Yes, every cloud coding agent has to send your code to its server to act on it. That is the deal. The delta here is three things. First, a secrets file specifically goes out unredacted, not even a pattern matcher for sk- or API_KEY=. Second, the contents get persisted to a named Google Cloud Storage bucket (grok-code-session-traces), not just processed transiently. Third, the repository upload is on by default and is not surfaced in the install or quickstart docs the researcher reviewed.

The honesty caveat that matters: the researcher proved transmission and storage, not training. Whether xAI trains on this data is a policy question. They did not and could not measure that side. But "uploaded and accepted with a 200" is its own fact, independent of what happens to the bytes afterward.

Then the whole repo leaves, even files the agent never opened

This is the finding I keep turning over. The researcher built a 12 GB repository entirely of random files the agent was explicitly told not to read. The prompt was "Reply with exactly: OK. Do not read or open any files.

The model turn channel moved 192 KB total across five requests. That is all the actual model inference traffic. The /v1/storage channel moved 5.10 GiB across 73 chunks of roughly 75 MB each, every single one returning 200. The ratio is about 27,800 to 1. There is no way to explain 5 GiB of upload from a 192 KB model interaction unless something else is being packaged and shipped wholesale.

12 GB never-read repo, single session
Channel A (model turns)192 KB total
Channel B (storage)5.10 GiB, 73 chunks
Ratio (B ÷ A)~27,800x
Failed uploads0
Every storage POST returned 200. Capture was truncated mid-stream, so the floor is 5.1 GiB, not the ceiling.

The mechanism is a git bundle. In a second, more controlled run on a real 298-file codebase, the researcher planted a unique marker string in src/_probe/never_read_canary.txt, told Grok not to open any files, and then captured the uploaded bundle. Running git clone on the captured artifact recovered the never-read file with the marker verbatim, plus the full commit history. Replicated on a second unrelated repo, same result.

So "the agent reads files and sends them to the model" is too narrow a description of what Grok Build does. The agent has a file-read path that feeds model turns, and a separate upload path that snapshots the workspace independently of what the agent chose to read. The second path does not care whether you asked it not to touch anything.

The opt-out does not opt out

xAI offers a setting called "Improve the model" in the account preferences at grok.com. It is the training opt-out. You would reasonably expect toggling it off to stop your code from leaving your machine.

It does not. The researcher turned the toggle off, re-ran the same test, and watched Grok Build still upload the entire repo as a git bundle to the same storage endpoint with a 200 response. The server-side settings response from /v1/settings still returned trace_upload_enabled: true, upload_enabled: true, and session_registry_enabled: true after the toggle was off.

The opt-out governs training, not transmission. Your repository leaves the machine either way. The telemetry upload to Mixpanel and the xAI events endpoint also continued returning 200. If you assumed the privacy toggle controlled collection, that is the assumption to revise.

What is and is not fair to say

The writeup is more careful than the headline. Several scope notes are worth keeping in mind before you treat any one claim as broadly as it might sound.

I appreciate that the writeup carries a "what we did not prove" section at the same length as the findings. Most security teardowns I read either skip it or bury it. This one enumerates the open gaps and labels them as such. That is how you build trust: show your work and your doubt.

The reliability bug, separate from the privacy angle

Worth flagging independently: the ~/.grok/upload_queue directory stages snapshots of roughly 3 GB per turn. Under load, the researcher observed it growing to tens of GB and exhausting disk space on the machine. This is a bug regardless of whether you care about the upload destination. A coding agent that silently fills your disk while you are trying to work is a real operational hazard, and it is not documented anywhere I could find in xAI's materials.

If you have been running Grok Build on a small partition or a CI runner with limited tmpfs, check ~/.grok/upload_queue periodically. The queue is supposed to drain after each upload, but on a large repo the staging alone can be larger than the available space before any drain happens.

Why this matters in context

Coding agents are at the point where the code they see is the code you see. Claude Code, OpenCode, Cursor, Continue, and now Grok Build all read and send repository contents by design. That is the only way any of them work. What differs is the policy around storage, redaction, and opt-out.

The Systima token-overhead study that hit the front page the same day measured what Claude Code and OpenCode send to the model endpoint. This Grok teardown measures what one agent sends to a second, separate storage endpoint that the model does not need for the turn. Different concern, same wire-level method, same lesson: the only honest accounting is the one you capture yourself.

I keep thinking about the gap between how a product is marketed and what it does on the wire. "Grok Build is an AI coding CLI" is accurate. "It uploads your repository to a named storage bucket that persists it independently of model turns, with no redaction of secrets, and the privacy toggle does not stop the upload" is also accurate. Both are true. The question is which one you want to know before you run it on your own code.

If you do run Grok Build, the pragmatic things are: assume the entire repo leaves, keep canary secrets in any codebase you test with it, and treat the "Improve the model" toggle as a training opt-out only, not a collection opt-out. If any of those assumptions are wrong in your case, a mitmproxy capture is the only way to know for sure. The researcher published the full method and artifacts, and the same rig works against any other CLI agent you might be evaluating.

The full analysis and reproduction script are at the researcher's gist, with SHA-256 hashes for every artifact and an explicit "what we did not prove" section. The Hacker News discussion is at item 48877371 and is worth reading for the pushback and the response from the researcher.