xAI's Grok Build CLI uploaded whole git repos — secrets included — to Google Cloud, bypassing its own opt-out. Here's the full breakdown, plus how to actually verify what your AI CLI is sending.
A wire-level security analysis found that xAI's coding CLI was shipping whole git repositories — untouched files, unredacted secrets, and full commit history included — to a Google Cloud bucket that never showed up in any onboarding flow. Here's what's been verified, what's still murky, and what to do if you've run the tool — including how to verify this kind of thing yourself instead of trusting a settings page.
If you've installed an AI coding CLI in the last few months, this is worth five minutes of your time — especially if that CLI was Grok Build, xAI's coding agent.
Update — July 13, 2026: Hours after this story spread, the official @SpaceXAI account posted that "no trace and code data is ever retained" for teams with Zero Data Retention (ZDR) enabled, and that the
/privacycommand in the CLI disables retention and deletes previously synced data for everyone else. Elon Musk followed up separately, saying all user data uploaded before now would be "completely and utterly deleted." Neither post is a formal security advisory, a scope disclosure, or a CVE — and critics have pointed out the stronger guarantee (ZDR) is an enterprise-only feature, while individual users have to know to run/privacythemselves. The sections below reflect what was known before this response; see the note at the end for how it changes things.
TL;DR
- xAI's Grok Build CLI uploaded entire git repositories — every tracked file plus full commit history — to a Google Cloud Storage bucket called
grok-code-session-traces, on a channel completely separate from normal AI inference traffic. - On a ~12 GB test repository, the model itself needed about 192 KB to do its job. The background uploader shipped 5.1 GB — roughly 27,800× more than the task required.
- A file the agent was told, in the prompt, not to touch still ended up in the uploaded bundle. So did fake secrets planted in a
.envfile, sent completely unredacted. - Turning off "Improve the model" in settings did not stop the uploads.
- Roughly a day after the research went public, the behavior appears to have been switched off server-side. xAI has not published a formal advisory, but the official @SpaceXAI account and Elon Musk both responded publicly on July 13 — see the update note above.
If you've pointed Grok Build at a repo with real credentials in it, treat this as a rotate-your-secrets-now situation. Here's the full breakdown.
What Is Grok Build, and Why It Matters
Grok Build is xAI's CLI coding agent — the same category as Claude Code, Cursor's CLI, or GitHub Copilot CLI. You run it from inside a project directory, and it reads files, explains code, and makes edits, the way any AI pair-programmer does. xAI, folded into SpaceX after their February 2026 merger, has marketed the tool with "local-first" language — the kind of framing that implies your codebase mostly stays put.
That's the exact claim this research undercuts.
The Discovery
A security research outfit called cereblab ran Grok Build CLI version 0.2.93 behind a mitmproxy capture, intercepting every packet leaving the machine during real sessions. What surfaced was two separate, simultaneous data channels:
-
The model-turn channel (
POST /v1/responses) — the expected one. Whatever files the agent actually opens get sent as context so the model can respond. Standard behavior for any cloud coding assistant. -
The storage channel (
POST /v1/storage) — a background process that packages your entire workspace as a git bundle and uploads it, independent of anything the agent touched.
The second channel is the whole story. It isn't mentioned in Grok Build's install or quickstart materials, and it runs by default.
The Numbers That Made This Go Viral
| Metric | Observed value |
|---|---|
| Test repository size | ~12 GB |
Model-turn channel (/v1/responses) |
~192 KB |
Storage channel (/v1/storage) |
5.1 GB across 73 chunks (~75 MB each), all HTTP 200 |
| Upload success rate | 100% — zero failed chunks |
| Ratio, storage vs. model-turn | ~27,800× |
| Destination |
grok-code-session-traces (Google Cloud Storage) |
For a task that genuinely needed 192 KB of context, the tool moved over five gigabytes off the machine in the background, with every single chunk landing successfully. That gap is the whole story in one row of a table.
Proof It Wasn't Just "Files the AI Happened to Read"
The obvious pushback — "of course a cloud coding agent sends your code somewhere, that's how it works" — doesn't survive the next test.
Cereblab planted a canary file in a test repo and, directly in the prompt, told Grok Build to give a one-word acknowledgment and avoid opening anything. The model-turn channel behaved exactly as instructed — it never touched the canary. But when the researcher reconstructed the git bundle captured on the storage channel, the untouched file was in there anyway, marker intact, along with the repository's full commit history. There's now a public GitHub repo that lets anyone reproduce this on a disposable canary repo and their own account.
That closes the loop: the storage upload isn't scoped to what the agent reads. It grabs the tracked contents of whatever directory you point it at.
Secrets Went Along for the Ride
Cereblab also planted a fake .env file — a labeled canary API key plus mock database credentials. Both channels, the live model request and the background storage upload, transmitted it completely unredacted. No masking, no filtering, no warning shown to the user.
If you've ever run Grok Build inside a repo where a real .env, credentials file, or config secret was tracked in git, this is the part worth losing sleep over.
The "Improve the Model" Toggle Doesn't Do What You'd Assume
Grok Build ships a setting called "Improve the model." Most developers would reasonably read that as "controls whether my code is used for anything beyond answering my prompt." Switching it off did not stop the storage-channel uploads — the settings endpoint kept reporting the upload behavior as active regardless of the toggle's state.
The opt-out governs training consent. It says nothing about whether your repository gets mirrored to a persistent bucket in the process.
Where the Data Actually Goes
The destination is a named Google Cloud Storage bucket, grok-code-session-traces, with object paths following a pattern like gs://grok-code-session-traces/repo_changes_dedup/v2/.... Sit with that for a second: this isn't "xAI infrastructure" in the way most users would assume from local-first marketing, and it isn't the model provider's usual inference path either. It's a specific, persistent, named cloud bucket that existed and was actively receiving repository data before anyone outside xAI knew it did.
Quick Timeline
- Grok Build v0.2.93 is the version behind the original wire-level capture.
- Cereblab publishes a full write-up on GitHub Gist, plus a public, reproducible test harness anyone can run against their own account.
- The write-up lands on Hacker News' front page, and several outlets (ByteIota, AI Weekly, GIGAZINE, ExplainX) cover it within a day.
- xAI's official changelog documents Grok Build v0.2.98 as the latest release on July 12, 2026 — with no mention of this behavior or any related fix.
- Within roughly a day of publication, cereblab reruns the same tests six separate times against the same client build and observes zero
/v1/storageuploads. The settings endpoint now returnstrace_upload_enabled: falseand a new flag,disable_codebase_upload: true. -
July 13, 2026: the official @SpaceXAI account states that ZDR-enabled teams retain no trace or code data, and that the
/privacycommand disables retention and deletes previously synced data for everyone else. Elon Musk separately says all data uploaded before now will be deleted. Still no formal security advisory, scope disclosure, or CVE.
A flag flipping silently on a server isn't the same thing as a disclosed fix.
Important Caveats — Read This Before You Panic Further
Good security reporting holds itself to the same bar it's asking a vendor to meet. A few things this research does not establish:
- It doesn't prove xAI trains its models on this data — that's a separate policy question the evidence doesn't settle either way.
- It doesn't prove every Grok Build account or plan tier behaves identically. xAI's enterprise documentation reportedly describes a different setup, including a Zero Data Retention (ZDR) mode said to prevent persistence at the inference layer.
- Only tracked files were shown to be swept into the git bundle — properly
.gitignore-excluded files weren't part of the captured evidence. - This is independent research from one security firm, not an official disclosure or a confirmed CVE. It's reproducible and wire-level, which earns it real weight — but it's still worth treating as one firm's findings rather than a settled institutional verdict.
This is a fast-moving story. If xAI publishes an official advisory after this goes up, some of the specifics above may shift — check the sources below for the latest.
What to Do If You've Used Grok Build CLI
- Rotate or revoke any real credentials — API keys, database passwords, tokens — that lived in a repo you've run Grok Build against.
- Audit your git history for secrets, generally. This is good hygiene regardless of this story, and commit history is exactly what the git bundle captures.
- Hold off on proprietary, regulated, or NDA-covered codebases until xAI publishes something official about scope and retention.
- Check for Zero Data Retention (ZDR) mode if you're on an enterprise plan — reportedly the stronger control here.
-
Don't rely on
.grokignorealone for anything sensitive already tracked in git — it hasn't been independently verified to strip already-committed secrets from the bundle. - Ask xAI directly whether any of your session or repository data has been stored, and request deletion in writing.
- If you manage a team, treat any AI coding CLI like a new third-party tool with broad filesystem access: least-privilege accounts, disposable credentials in dev environments, and no production secrets anywhere near a tool whose data path isn't fully documented.
How to Actually Verify What Your AI CLI Is Sending (Not Just Trust the Settings Page)
Fair warning: this section assumes some comfort with networking and sandboxing tools. Skip to the Sources if that's not your thing.
If a toggle labeled "Improve the model" doesn't govern a background upload channel, the only way to know what's actually happening is to watch the wire yourself. Here's the stack that would've caught this before cereblab did.
1. TLS-terminating proxy, not passive sniffing
tcpdump won't help you here — everything's encrypted. You need something that MITMs the TLS session:
mitmproxy --mode transparent --showhost \
--set confdir=~/.mitmproxy \
--ssl-insecure
Point the CLI's process at it via HTTPS_PROXY/HTTP_PROXY env vars, install the mitmproxy CA cert in the process's trust store (not just the system one — Node/Go binaries often bundle their own cert pool via NODE_EXTRA_CA_CERTS or vendored cacert.pem), and diff every distinct Host header against what the docs claim the tool talks to. Anything hitting a bucket-style endpoint (storage.googleapis.com, s3.amazonaws.com, unfamiliar *.run.app Cloud Run targets) that isn't the documented inference endpoint is your signal.
2. Egress allowlisting at the OS/network-namespace level, not app-level toggles
Never trust an in-app setting to be the actual boundary. Enforce it outside the process:
-
Linux: run the CLI inside a network namespace with
nftablesegress rules that allowlist only the documented API host by IP/CIDR (pin it, don't rely on DNS-time resolution which the binary controls anyway):
nft add table inet cli_sandbox
nft add chain inet cli_sandbox output { type filter hook output priority 0 \; policy drop \; }
nft add rule inet cli_sandbox output ip daddr <known-inference-ip>/32 tcp dport 443 accept
- Firejail/bubblewrap for a lighter sandbox if full netns is overkill:
firejail --net=none --whitelist=$HOME/project grok-build
then punch a hole only for the specific proxy if you need connectivity, via --netfilter with an explicit rule file.
- macOS: Little Snitch or LuLu rules per-binary, deny-by-default, alert-on-first-connection.
3. Syscall/eBPF-level monitoring — catches what proxying can't
A proxy only sees what respects HTTPS_PROXY. A binary can ignore env proxy vars entirely and dial raw sockets. For that you need syscall visibility:
-
Falco or Tetragon (eBPF) watching for
connect()syscalls from the CLI's PID/cgroup, independent of whatever the app-layer claims:
- rule: Unexpected egress from AI CLI
condition: >
outbound and proc.name="grok-build"
and not fd.sip in (known_inference_ips)
output: "Unexpected connection (dest=%fd.rip dport=%fd.rport)"
- Cheaper alternative:
strace -f -e trace=network -p <pid>during a session, ornethogs/bpftracefor a quick per-process bandwidth check — a 192KB task pushing 5GB out is visible in seconds without any deep tooling.
4. Treat tracked-file exposure as a git-hygiene problem, independent of any specific tool
Since the exfil vector was "everything tracked in git," not "everything the model reads":
-
gitleaks detect --source . --verboseortrufflehog git file://. --since-commit HEAD~50on any repo before you point an agent at it — this catches historical secrets the CLI's own redaction (if any) will never see, because they're pre-existing tracked content, not live prompt context. - Pre-commit hook via
detect-secrets scan --baseline .secrets.baselineso nothing new lands trackable in the first place. - For anything genuinely sensitive: keep secrets in an untracked
.envloaded via a secrets manager (Vault, SOPS+age, or even justdirenvpulling from a keychain) — never committed, never in the working tree the agent's git bundle would sweep.
5. Container isolation with a scoped bind-mount, not "point it at your whole machine"
Run the CLI in a container that only sees the one repo, with no access to ~/.ssh, ~/.aws, global git config, or anything outside the mount:
docker run --rm -it \
--network=cli-egress-restricted \
-v "$(pwd)":/workspace:rw \
--read-only --tmpfs /tmp \
grok-build-runtime
Pair the cli-egress-restricted Docker network with an iptables-based egress allowlist on the bridge interface. This turns "the tool can see your whole filesystem and dial anywhere" into "the tool can see one mounted dir and dial one IP."
If you'd rather not hand-roll the docker run flags every time, here's a minimal Dockerfile and docker-compose.yml that pin the same constraints declaratively:
# Dockerfile
FROM node:20-slim
# Non-root user — never run an AI CLI as root against your code
RUN useradd --create-home --shell /bin/bash runner
WORKDIR /workspace
# Install the CLI here (pin the version — don't float to `latest`)
RUN npm install -g grok-build@0.2.98
USER runner
ENTRYPOINT ["grok-build"]
# docker-compose.yml
services:
grok-build:
build: .
image: grok-build-runtime
networks:
- cli-egress-restricted
volumes:
- ./:/workspace:rw # only this repo, nothing else
read_only: true # image filesystem is immutable
tmpfs:
- /tmp # writable scratch space only
cap_drop:
- ALL # no extra Linux capabilities
security_opt:
- no-new-privileges:true
environment:
- HTTPS_PROXY=http://host.docker.internal:8080 # points at mitmproxy running on your host machine
extra_hosts:
- "host.docker.internal:host-gateway" # makes the host resolvable on Linux too, not just Mac/Windows
networks:
cli-egress-restricted:
driver: bridge
internal: false # flip to true once you've allowlisted the inference IP via iptables on the bridge
Run it with docker compose run --rm grok-build, and pair the HTTPS_PROXY line with the mitmproxy setup from step 1 above so every session gets wire-audited by default, not just when you remember to check. Bump the pinned version deliberately, not automatically — that's the only way you'll know if a future release changes what crosses the wire.
The common thread: don't audit these tools by reading their settings page. Audit them by watching the wire and constraining the sandbox, because — as this story shows — the two aren't guaranteed to agree.
The Bigger Lesson
Every cloud-based coding agent has to send some code somewhere — that part isn't the scandal. The problem is the gap between what a settings page promises and what actually leaves your machine at the wire level. A toggle labeled "Improve the model" implies control over data use. It didn't stop a background process from mirroring an entire repository — secrets and history included — to a bucket that was never mentioned anywhere in onboarding.
Before pointing any AI coding agent at a codebase you can't afford to leak, it's worth checking what actually crosses the wire, not just what the settings page claims. In 2026, that's not paranoia — it's due diligence.
One closing note on that "straight answer": xAI's public response so far — ZDR for enterprise, /privacy for everyone else — is a real step, but it's a statement on X, not a security advisory, and it doesn't change what happens by default the first time someone runs the tool without knowing to flip that setting. Worth watching whether anything more formal follows.
Have you run Grok Build against a real project? Curious whether anyone's gotten a straight answer from xAI support on retention — drop it in the comments.
Sources & Further Reading
- Original viral thread — International Cyber Digest (X/Twitter)
- cereblab's full wire-level analysis (GitHub Gist)
- Reproducible test harness (GitHub)
- ByteIota: "Grok Build CLI Uploads Your Entire Repo to xAI Servers"
- ExplainX: wire-level breakdown, with the July 13 update
- GIGAZINE: English-language coverage
- Penligent: architecture breakdown and mitigation checklist
- AI Weekly: alert summary
- @SpaceXAI's official response on X (July 13, 2026)
- Elon Musk's follow-up statement on data deletion (X, July 13, 2026)

Top comments (0)