What Happened
AI Security · AI Agents · Wire-Level Teardowncereblab · 12 Jul 2026 · record to 25 Aug 2026
Executive summary · one-page brief
“Do Not Open Any Files” — and the Whole Repo Shipped Anyway
A wire-level teardown of Grok Build, the coding CLI from xAI — renamed SpaceXAI on 6 July 2026 — showed that build 0.2.93 ran two independent channels: the model's own file reads, and a separate background upload of the entire workspace as a git bundle. The permission prompt governed only the first. In the decisive control run the agent was told to open nothing — it obeyed, and the repository left the machine anyway, full git history inside it. The upload was disabled server-side the next day; what it revealed about the tool's consent model is why this page still stands six weeks on.
By the Numbers one 12 GB repo, one session
- 27,800×more data left the machine than the model's turns needed
- 5.10 GiBuploaded via /v1/storage — against 192 KB of model traffic
- 0settings found that stopped the upload, before the 13 Jul fix — “I did not find one”
- 2unrelated repositories — the same never-read canary recovered
What Was Proven — and What Was Not graded by standing, strongest first
| How firm | What | Who says so |
|---|---|---|
| Confirmed | At launch, xAI marketed Grok Build as “local-first,” stating no source code was transmitted to its servers | DevOps.com's launch coverage, 15 May 2026, read directly |
| Confirmed | On 13 July the whole-repository upload stopped; the server began returning disable_codebase_upload: true — confirmed independently on a second account | cereblab's own retest; developer Peter Dedene's own account, posted on X |
| Confirmed | xAI (renamed SpaceXAI six days earlier) publicly acknowledged that data retention had been on by default for non-enterprise users, and Musk pledged to delete all previously-uploaded data | SpaceXAI's own X post; The Register, 14 Jul 2026 |
| Confirmed | SpaceXAI open-sourced the Grok Build CLI under the Apache License on 16 July; the upload code was found still present in the release, altered rather than removed | The Register, 16 Jul 2026, citing developer Simon Willison's own review |
| Confirmed, but not verifiable here | Grok Build 0.2.93 ran a second channel that bundled the whole repository, full git history included, and uploaded it via /v1/storage regardless of whether the agent had been told to read anything; on a 12 GB test repo, that channel moved 5.10 GiB against 192 KB of model-turn traffic | cereblab's wire capture, with a public reproduction harness — not independently reproduced by a named third party in the sources below |
| Confirmed, but not verifiable here | Cloning a captured bundle recovered a file the agent had explicitly been told not to open, verbatim, plus full git history; replicated on a second, unrelated repository | cereblab, as above |
| Confirmed, but not verifiable here | A tracked .env file's secrets were transmitted unredacted, both in the model-turn traffic and in the storage upload | cereblab, as above |
| Confirmed, but not verifiable here | Turning off “Improve the model” did not stop the bundle upload; the server continued to report trace_upload_enabled: true | cereblab, as above |
| Unconfirmed | That the pledged deletion of previously-uploaded data was actually completed | Not found in any source below, as of 25 Aug 2026; The Register's own 14 Jul report says the same about its own coverage |
| Unconfirmed | That “other researchers” independently confirmed the finding on their own repositories, and that Codex and Anthropic “independently found indirect evidence” of eight further private repositories fully uploaded | cereblab's own site (unnamed, no linked artifact); developer Peter Dedene's own account of what he says those parties found — neither corroborated by a statement from OpenAI or Anthropic |
| Not public | Whether SpaceXAI trains its models on data collected this way | cereblab's own gist states plainly this was not proven either way: “upload/storage ≠ training” |
Timeline
How It Unfolded eleven days from teardown to open source, then a five-week silence on completion
- 2026-02-02SpaceX completes its all-stock acquisition of xAI.
- 2026-05-15Grok Build is covered in early testing, marketed as “local-first” — trade press reports xAI's own claim that no source code is transmitted to its servers.
- 2026-07-06xAI's public accounts rebrand as SpaceXAI.
- 2026-07-12cereblab publishes the wire-level teardown of grok build 0.2.93, with SHA-256-hashed evidence and a public reproduction harness.
- 2026-07-13The upload stops: the server begins returning
disable_codebase_upload: true. Developer Peter Dedene reports the same flag on his own account. - 2026-07-14The Register and The Hacker News report the findings. SpaceXAI posts on X explaining what “Improve the model,” ZDR and the new /privacy command each cover. Musk publicly pledges to delete all previously-uploaded user data — not yet independently confirmed as complete.
- 2026-07-16SpaceXAI open-sources the Grok Build CLI under the Apache License and resets usage limits. Independent developer Simon Willison reviews the released source: the upload code is still there, altered to reverse the behaviour rather than removed.
- 2026-07-22cereblab retests grok build 0.2.106 and reconfirms the fix holds.
- still openWhether the pledged deletion was completed remains unconfirmed. No CVE identifier or formal vendor security advisory for this behaviour appears in any source below, as of 25 Aug 2026.
The Argument
Two Channels, Different Rules the permission prompt sees only one
Channel A · read-driven
/v1/responses
- Carries only what the agent actually opened.
- This is the channel the permission prompt governs.
- 192 KB across five requests in the test session.
- Never-read files are genuinely absent here.
Channel B · repo-driven
/v1/storage
- Bundles git-tracked files plus full history.
- Indifferent to what the model read — or didn't.
- 5.10 GiB from the same session; 73 chunks, all HTTP 200.
- Destination: a Google Cloud Storage bucket.
The Canary That Never Was Read prose left · the decisive run right
The byte ratio alone is suggestive: 192 KB of model turns cannot carry 5.10 GiB, so the storage channel must be a whole-repository snapshot rather than a by-product of reading. But the decisive proof is per-file. A run was prompted “Reply with exactly: OK. Do not read or open any files.” The agent complied and opened nothing — and POST /v1/storage still returned 200, carrying the repository as a git bundle. Cloning the preserved bundle recovered a planted canary file the agent had never touched, verbatim, together with the full four-commit history. It replicated on a second, unrelated codebase. The harness that does this is public, with its method published in full — the account above is cereblab's own, and is not known to have been independently re-run by anyone else.
- OKthe agent's entire reply — it opened nothing
- 4commits recovered from the bundle, in full
- ×2codebases the recovery was repeated on
On the Wire one session · two destinations
| What went up | Channel | Evidence |
|---|---|---|
| The repository, as a git bundle | /v1/storage | 73 chunks of ~75 MB, every one HTTP 200; cloned back to recover a never-read canary. |
| A .env, unredacted | both | API key and DB password in clear in a 48 KB request body, and again inside a session-state archive. |
| Destination bucket | GCS | Named in the binary's strings and in staged metadata paths — corroborated three ways. |
Three Switches, None of Them the Brake assumption vs. behaviour, before the 13 Jul fix
| Control | What a developer assumes | What it actually did |
|---|---|---|
| “Improve the model” toggle · default ON | opts me out of data collection | governed training/retention policy, not transmission. Switched off, the server still returned trace_upload_enabled: true and the bundle still uploaded — until the 13 Jul server-side fix. |
| /privacy command (added after the fix) | stops the sending | a data-retention setting — “not a block on what's sent”, wire-tested by cereblab. What actually stopped transmission was the separate disable_codebase_upload server flag. |
| Any user-side off switch | there must be one somewhere | none was found before 13 Jul. The upload stopped only when SpaceXAI flipped a flag on its own servers — a remedy a user could not reach. |
Bottom line
The failure is in the consent model, not any single line of code. The prompt asked “may I read?” while a second channel bundled git-tracked files plus full history and shipped them regardless — and the only thing that ever stopped it was the vendor, on its own servers.
Reframe
Your exposure is whatever the tool uploads — never whatever it reads.
What Others Add
Why a Deleted Secret Still Shipped the exposure chain
- 01Commita secret, months ago
- 02Deletefrom the working tree
- 03Persistit lives on in git history
- 04Bundletracked files + history
- 05Uploadregardless of reads
- 06Rotatethe only real remedy
How the Field Compares cereblab's own cross-tool tests
| Tool | Uploads the whole repository? | Standing |
|---|---|---|
| Claude Code | No — only files it opens | Confirmed, but not verifiable here |
| Codex | No — only files it opens | Confirmed, but not verifiable here |
| Gemini | No — only files it opens | Confirmed, but not verifiable here |
| Grok Build (0.2.93, before the fix) | Yes — whole repo plus git history, to the cloud | Confirmed, but not verifiable here |
The Company's Own Words, and What Followed read directly, not only through press paraphrase
SpaceXAI's own public statement, read directly, says: “Since launch, Grok Build has fully respected zero data retention (ZDR)… In the early beta, data retention was enabled by default for non-ZDR users. Based on your feedback, we changed this.” That is the company's own account of what happened, in its own words — an admission that retention defaulted to on for everyone outside its enterprise tier, not only a description of a fix. It frames the episode as a beta-era default it has since corrected, rather than as the transmission bug cereblab's wire capture describes; both statements are given here side by side, neither resolved in favour of the other. What SpaceXAI has not done, in any source below, is publish a security advisory, a changelog entry, or a CVE for the behaviour — its account of events lives in social posts, not in a document a reader could later cite as the vendor's own record. Two further sentences of that statement bear directly on the finding, and are not reconciled with it anywhere in the sources below: SpaceXAI says “all users have always had the ability to disable data upload in the CLI” and that “when data upload was disabled, this choice was respected” — a flat denial of the claim that no user-side setting stopped the bundle. It also dates its own change to “starting on July 12th,” a day before the server flag was observed to change.
Conclusion
Recommendations highest-return first
- Rotate every credential reachable in tracked git history — deleting it never removed it, and a pledge to erase uploaded data cannot un-ship what already left the machine.
- Verify on the wire, not in the prompt — a permission dialog describes one channel; measure what actually leaves the machine, the way a public reproduction harness lets a third party do.
- Demand default-off — a retention toggle you must run every session is not consent, and it is a different control from the one that actually stops transmission. The default is the policy.
- Treat a vendor-side fix as a pause, not a close-out — the upload code itself was reported still present, merely altered, after the fix; and whether previously-uploaded data was actually deleted remains unconfirmed. Prefer tools whose off switch you hold locally and can verify.
Where it lands
Any agentic coding tool whose consent surface is scoped to a narrower channel than its transmission has this bug — whatever its logo. Grok Build gated reads while a second channel shipped the repository, and cereblab found no user-side setting that stopped it — which SpaceXAI denies: the uploads ceased only when the vendor — xAI, renamed SpaceXAI days before — disabled them on its own servers, days after being caught, and the company has since open-sourced the tool, pledged to delete what it collected, and said nothing in the form of a formal advisory. A remedy you cannot reach is not a control. The right default is off.