July 17, 2026
Grok Build CLI Was Quietly Uploading Entire Codebases to Google Cloud — What This Means for Your…
A wire-level security analysis found that xAI’s coding CLI was shipping whole git repositories — untouched files, unredacted secrets, and…

By freerave
12 min read
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, any settings page, or any DevOps documentation. If you've wired an AI coding agent into your dev workflow, your CI runners, or anywhere near a secrets-bearing repo, this is worth five minutes of your time.
Most coverage of this story has framed it as a "consumer AI privacy scandal." That framing misses the part that should actually worry infrastructure and platform engineers: this wasn't a model behaving unexpectedly during inference. It was a background process, separate from the AI entirely, silently mirroring tracked repository contents — the same class of behavior that, if it showed up in a CI plugin or a build-time dependency, would get an incident ticket opened within the hour.
Why This Belongs in a DevOps Conversation, Not Just a Security One
If you've adopted an AI CLI as part of a developer's local workflow, chances are it's already touching directories that also feed your pipelines — shared .env conventions, local copies of infra-as-code repos, Terraform state directories, CI config files with embedded tokens. A tool with this kind of undocumented exfiltration behavior sitting on a developer laptop is one bad repo checkout away from becoming a supply-chain incident, not just a personal privacy one.
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. For a platform team, that distinction matters: the default behavior for a developer laptop running Grok Build without enterprise ZDR is unchanged by this response. The sections below reflect what was known before this response; see the note at the end for how it changes things.
TL;DR
- 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 explicitly 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 — including CI/CD tokens, cloud provider keys, or database connection strings — treat this as a rotate-your-secrets-now situation.
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 — which, from a DevOps standpoint, means it runs by default on every developer machine and every ephemeral CI container that installs the tool, with no flag to review before first use.
The Numbers That Made This Go Viral
MetricObserved valueTest repository size~12 GBModel-turn channel (/v1/responses)~192 KBStorage channel (/v1/storage)5.1 GB across 73 chunks (~75 MB each), all HTTP 200Upload success rate100% — zero failed chunksRatio, storage vs. model-turn~27,800×Destinationgrok-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 — which, in a CI context, could be your entire monorepo.
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, Kubernetes secret manifest, or cloud provider config 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. If you rolled this out org-wide based on that toggle being off, it's worth revisiting that assumption.
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 — and no change to what happens by default for a developer who hasn't run/privacyor isn't on an enterprise ZDR plan.
A flag flipping silently on a server isn't the same thing as a disclosed fix — and for anyone running compliance-sensitive workloads, "silently fixed, never disclosed" is its own finding.
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.
What to Do If You've Used Grok Build CLI
- Rotate or revoke any real credentials — API keys, database passwords, CI/CD 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 platform or DevOps team, treat any AI coding CLI like a new third-party tool with broad filesystem access: least-privilege accounts, disposable credentials in dev and CI 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
This section assumes some comfort with networking and sandboxing tools.
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 — and the same stack you'd want in a pre-production checklist before letting any AI CLI near a CI runner.
1. TLS-terminating proxy, not passive sniffing
tcpdump won't help here — everything's encrypted. You need something that MITMs the TLS session:
mitmproxy --mode transparent --showhost \
--set confdir=~/.mitmproxy \
--ssl-insecuremitmproxy --mode transparent --showhost \
--set confdir=~/.mitmproxy \
--ssl-insecurePoint 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 acceptnft 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-buildfirejail --net=none --whitelist=$HOME/project grok-buildthen 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)"- 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-runtimedocker run --rm -it \
--network=cli-egress-restricted \
-v "$(pwd)":/workspace:rw \
--read-only --tmpfs /tmp \
grok-build-runtimeIf 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
RUN useradd --create-home --shell /bin/bash runner
WORKDIR /workspace
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
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
environment:
- HTTPS_PROXY=http://host.docker.internal:8080
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
cli-egress-restricted:
driver: bridge
internal: false# Dockerfile
FROM node:20-slim
RUN useradd --create-home --shell /bin/bash runner
WORKDIR /workspace
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
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
environment:
- HTTPS_PROXY=http://host.docker.internal:8080
extra_hosts:
- "host.docker.internal:host-gateway"
networks:
cli-egress-restricted:
driver: bridge
internal: falseRun 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, and the one worth carrying into any platform-engineering checklist: 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 for DevOps and Platform Teams
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 the 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.
For teams thinking about adopting AI coding tools as part of a standard developer image or CI pipeline, this is a reminder that "AI tool" doesn't mean "exempt from the same vendor security review you'd run on any other third-party binary with filesystem and network access." 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, and it belongs in the same review process as any other supply-chain dependency.
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 for a developer machine or CI runner that hasn't been configured either way. Worth watching whether anything more formal follows before treating this as resolved for a team rollout.
Have you run Grok Build against a real project, or rolled it out to a team? 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)