xAI’s Grok Build CLI (grok 0.2.93) uploads the entire workspace it is pointed at, including git history, to a Google Cloud Storage bucket on every run, regardless of which files the agent reads, according to a wire-level teardown by cereblab. The question stops being what code fragments the model sees and becomes whether the directory you launch it from holds anything you cannot afford to send to xAI.
What the wire evidence actually shows
The cereblab teardown of grok 0.2.93 produced three captured behaviors worth separating. The binary was installed via curl -fsSL https://x.ai/cli/install.sh | bash and authenticated with a consumer X/SuperGrok browser login, not an API key.
First, when Grok reads a file, including a .env secrets file, it transmits the contents verbatim and unredacted across two channels: serialized into the POST /v1/responses model-turn body, and packaged into a session_state archive uploaded and accepted via POST /v1/storage, according to the cereblab teardown. The .env left the machine on both paths, in cleartext, with no redaction observed.
Second, the upload is not bounded by what the agent reads. With the prompt “reply OK, do not read any files” run against a real codebase, Grok uploaded the whole repository as a git bundle via POST /v1/storage, and cloning the captured bundle recovered a never-read canary file verbatim. The model never opened that file. The upload sent it anyway.
Third, the methodology is reproducible. cereblab used mitmproxy with a trusted login-keychain CA that Grok does not certificate-pin against, placed unique canary markers in every file, and race-copied ~/.grok/upload_queue/* before it drained. A reproduction repository is published at github.com/cereblab/grok-build-exfil-repro, with an evidence appendix and an explicit list of what was not proven. The lack of certificate pinning is what makes the whole teardown possible: a vendor that pinned its TLS would have blocked the intercept, and grok does not.
Two channels, and why the ratio matters
The headline number from the teardown is a ratio, not a total. On a 12 GB repository of never-read random files, POST /v1/storage moved 5.10 GiB, all uploads accepted, zero failures, according to the cereblab teardown. The model-turn channel moved 192 KB in the same run. That is roughly 27,800x more bytes leaving through the storage channel than through the model, on a workload where the model was instructed not to read anything.
The functional distinction between the two channels is the part that earns the ratio its weight. The model-turn channel is load-bearing: it is how the agent works, carrying the context the model reasons over. A user cannot opt out of it without opting out of the product. The storage channel is additive. Nothing about answering “reply OK” requires shipping a git bundle of the repo, and yet the CLI ships it on every run, and the toggle that should disable it does not. One channel is necessary and consented by use; the other is parallel, default-on, and undisableable through the UI.
The ratio is what makes this a category shift rather than a degree change. If the storage upload were a mirror of model context, the two channels would track each other. They do not. The storage channel is pinned to the codebase on disk; the model channel is pinned to what the agent reads; and the gap between them is five orders of magnitude. Defenders who model coding-agent data flow as “what the model sees” will undercount the exposure by a factor in the tens of thousands on a real repo.
The part a defender should dwell on is that the upload path does not appear to have a ceiling that would save you from a large checkout. Across the captured sweep the only failed responses were a model-usage quota rejection on /v1/responses and one unrelated not-found error; no storage size cap was hit. If your monorepo is 20 GB, the mechanism that moved 5.10 GiB here has no observed reason to stop.
The GCS destination, and the toggle that does not turn it off
The upload lands at a Google Cloud Storage bucket named grok-code-session-traces, not AWS S3. The bucket name appears verbatim in the binary and in a captured metadata.json, according to the cereblab teardown.
The teardown race-copies a ~/.grok/upload_queue/* directory before it drains, which is consistent with a persistent upload queue. Combined with the zero-failure sweep across the 12 GB run, the storage path reads as production telemetry, not a debug leftover.
The harder finding is the toggle. The whole-workspace upload is active by default, and disabling “Improve the model” does not turn it off. After the toggle was flipped, /v1/settings still returned trace_upload_enabled: true. The named, user-facing disable surface for telemetry does not disable the storage channel.
Why this widens the trust boundary
A coding CLI that sends only the code it reads is bounded by the files you let it touch. A CLI that uploads the whole workspace regardless of reads is bounded only by the directory you launch it from. Those are different threat models, and the difference is the story.
Prior framing of coding-agent telemetry, including Groundy’s July reporting on Grok, treated the data path as selective: code fragments sent inside model context, gated by what the agent chose to read. The cereblab gist is the first wire-level evidence of a bulk whole-workspace upload that is independent of model reads. That is a side channel, not a louder version of the main channel. The blast radius of a read-bound leak is “the files the agent opened,” which a careful user can keep small. The blast radius of a workspace-bound leak is “the entire checkout plus its history,” which a careful user can only keep small by never pointing the tool at anything sensitive.
That distinction matters for how you react. If the behavior were a recursive home-directory scan, the only safe posture would be to never install it. Because it is workspace-scoped, the safe posture is to scope the workspace: never point grok at a directory that contains secrets, or at a parent of one. The default habit of running coding CLIs from ~, or from a monorepo root that happens to contain .env files, is exactly the case this bites. So is the habit of running it inside a checkout that carries vendor branches, customer fixtures, or archived credentials in git history, because the bundle includes history, not just the working tree.
The second-order consequence lands on employer device policy. A tool that exfiltrates its working directory by default, on every run, with no working disable, is not compatible with “this can sit next to ~/.aws/credentials.” Security teams that approve coding CLIs on developer laptops now have to treat grok as requiring a secrets-isolation boundary, the way they would treat any untrusted binary with disk and network access. The approval question stops being “is this vendor trustworthy” and becomes “can we let this run where secrets live,” and on the captured evidence the answer to the second is no.
Consumer auth, not API keys
Grok Build is a consumer product. grok.com distributes the CLI (the install path also offers a PowerShell variant, irm https://x.ai/cli/install.ps1 | iex) and states Grok Build is “Now powered by Grok 4.5” with “Early access for SuperGrok and X Premium+ subscribers.” The SuperGrok plan lists “Access to Grok Build” among its benefits, placing the coding CLI in a consumer-subscription tier rather than an enterprise or API-key product with contractual data terms.
The authentication flow matches. Login is a consumer-identity flow, Google, X, Apple, or email, bound to xAI’s consumer Terms of Service and Privacy Policy, consistent with the gist’s finding that the CLI authenticates via a consumer X/SuperGrok account rather than an API key.
The trust surface this creates is the point. When an enterprise buys an API product, there is usually a data processing agreement, zero-retention terms, or a contractual carve-out that defines what the vendor may do with the payloads and how long it may keep them. When an engineer logs into grok with a personal X account on a work laptop, none of that applies. The workspace upload lands under consumer terms. The remediation an enterprise can demand, deletion guarantees, enforceable training opt-outs, audit logs, is not on the table because the relationship is consumer-to-vendor, not enterprise-to-vendor. xAI’s own homepage demonstrates Grok Build as an interactive coding agent that reads files, greps, and edits source, which is the read-driven, file-accessing behavior the gist shows feeding both channels.
This is also why “just ask xAI to delete it” is weaker than it sounds. A consumer has the deletion rights a consumer has, under a consumer privacy policy, enforced the way consumer privacy policies are enforced. There is no contract to point at.
What the analysis does and does not prove
The teardown proves transmission, acceptance by the server, and storage. It does not prove xAI trains on the data. cereblab treats training as a separate policy question and is explicit about the line. Conflating exfiltration with training is the easy overclaim to make and the one to avoid. What is proven is already enough to change how the tool should be deployed; the training question changes how alarmed to be about the stored copy, and it is genuinely open.
Three scope limits are worth naming before reacting:
- The tested
.envwas git-tracked, and the reproduction repo states the only thing that keeps a file out of the bundle is gitignoring it (the bundle carries tracked files only). Gitignoring a secrets file is therefore a real mitigation for the bundle path; it does nothing for any secret already committed to history, which the bundle carries. - Canary values were not real-format, high-entropy tokens. The existence of a redactor for, say, an
sk--prefixed key is unproven. Do not conclude that no redactor exists either; the test could not see one way or the other, because the canaries did not look like real keys. - No storage size cap was reached, but the sweep did not exhaust every repo shape. Absence of a ceiling across the tested range is not proof of no ceiling at all.
The git-tracked point has a second-order sting worth noting. A secrets file committed to git is already an incident, and the standard remediation is rotate and rewrite history. With this upload path, the contents are also sitting in a GCS bucket under consumer terms, so “rotate and rewrite history” no longer closes the exposure. The blast radius is the bucket, not just the repo, and the bucket is not yours to clean.
How to run it safely: the container verdict
Treat grok like any untrusted binary with disk and network access. The operational pattern is the same one you would apply to any tool you do not fully trust with your source tree, and it is now the baseline rather than the paranoid option.
The burden has shifted. Before this evidence, the reasonable ask was that xAI document its telemetry clearly and ship a working disable. After it, the reasonable ask is that teams run the CLI inside a secrets-isolation boundary regardless of what the docs say, because the toggle does not work and the upload is not bounded by reads. On that basis, grok’s coding-agent tooling drops out of the set of CLIs an employer can permit on developer machines without a separate isolation boundary. That is a strong statement, and it follows directly from the captured payloads: a default-on, settings-resistant, read-independent upload of the entire workspace to a vendor bucket is not compatible with running next to live credentials.
If you must use it on real code, the cheap mitigations stack. Scope --cwd tightly. Strip .env and credential files out of the checkout before launching, and scrub git history of anything sensitive, because the bundle carries history. Consider network egress controls so that even the container’s uploads are visible to a proxy you control. None of these are substitutes for not having secrets in the mounted tree in the first place.
How this compares to Claude Code, Cursor, and other coding CLIs
The fetched evidence is Grok-only. Cross-tool comparison here is hedged and drawn from prior reporting rather than fresh wire-level teardowns of Claude Code or Cursor, neither of which was re-tested for this piece.
What can be said is structural. Prior coverage of coding-agent data handling, Groundy’s July Grok piece included, framed the data path as selective telemetry: code fragments traveling inside model context, gated by what the agent reads. The cereblab gist is the first wire-level evidence the brief contains of a bulk whole-workspace upload that is independent of model reads. Wire-level teardowns of Claude Code and Cursor are not carried in the brief, so the claim “Claude Code does not do this” or “Cursor does not do this” cannot be made here. What can be said is that the two-channel, read-independent architecture cereblab found in grok 0.2.93 is the pattern to test the others against, and the methodology ports directly: mitmproxy, canaries, and a race on the upload queue will find an equivalent side channel if one exists.
The honest position is that grok is the tool with the wire evidence against it today, and the others are untested at this depth. Treat the comparison as an agenda for testing, not a ranking.
What to watch for next
Versions and vendor statements will rotate quickly; the durable parts are the architecture, the toggle, and the auth surface.
Check for an official xAI response before treating the framing as final. A vendor statement or a 0.2.94 patch could change any of the three findings, and the 0.2.93 label will date fast. Replay the repro on 0.2.94 and later before assuming the behavior either persists or is fixed. The repro repo exists precisely so that re-running it is cheap, and a SHA rotation without a behavior change would be its own kind of signal.
The things that will not rotate as fast are the structural ones. A two-channel architecture, where an in-context model-turn path is shadowed by a side-channel storage upload, is the part worth remembering even after the version number moves. A default-on toggle that the settings UI does not disable is the part worth verifying in every release. A consumer-auth trust surface, where the coding agent authenticates as a personal subscription rather than an enterprise API key, is the part that determines which remediation options are even on the table. And the operational pattern, running untrusted coding CLIs inside a secrets-isolated container with no mounted credentials, holds regardless of what xAI ships next. If a future version fixes all three findings, the container habit still costs nothing and protects against the next tool that does the same thing.
Frequently Asked Questions
Does the upload include .gitignored files like local .env?
The wire evidence confirms the upload targets git-tracked files and history. The cereblab analysis explicitly notes that the tested .env was git-tracked, and the reproduction repo states that gitignoring a file is the primary mechanism to keep it out of the bundle. The behavior for .gitignored files remains untested, so the upload path for those files is unproven.
Does xAI train on the uploaded workspace data?
The teardown proves transmission, server acceptance, and storage in a GCS bucket. It does not prove xAI trains on the data. The researchers treat training as a separate policy question and explicitly state that the wire evidence cannot confirm whether the stored payloads are ingested into model training pipelines.
How does the upload mechanism handle large repositories?
For larger repositories, the CLI switches to a direct-GCS multipart upload flow. The captured evidence shows a 3 GB repository uploading via POST /v1/storage/multipart/init followed by PUT requests to storage.googleapis.com in 50 MB parts. The only non-200 responses observed were model-usage quota rejections, indicating no observed storage size cap.
What authentication method does the CLI use?
The CLI authenticates using a consumer X or SuperGrok browser login, not an API key. This binds the data upload to xAI’s consumer Terms of Service and Privacy Policy, meaning enterprise data processing agreements or zero-retention contractual terms are not available to users running the tool on work laptops.
Can the upload be disabled via the settings UI?
Disabling the ‘Improve the model’ toggle does not stop the workspace upload. The cereblab teardown shows that after flipping the toggle, the /v1/settings endpoint still returned trace_upload_enabled: true, indicating the user-facing disable surface is cosmetic with respect to the storage channel.