What Your AI Coding CLI Actually Sends Home
A wire-level analysis of xAI's Grok Build CLI revealed it uploads entire repositories — including .env secrets and unread files — to cloud storage, with no way to opt out. This post covers what happened, how to verify your own tools, and the practical security boundaries every team shipping with AI assistants needs.
Last week, a security researcher published a wire-level analysis of what xAI's Grok Build CLI actually sends home. It shot to the top of Hacker News with 233 points and 114 comments in hours. The findings were stark: the CLI uploads your entire repository — every tracked file, every commit in your git history — to xAI's cloud storage. It does this even when you tell the agent not to read any files. It does this even when you turn off the "Improve the model" toggle. On a 12 GB repo of random files the agent never touched, it shipped 5.1 GiB before the capture was stopped.
The HN thread was what you'd expect: outrage, Elon jokes, and a GitHub Copilot engineer jumping in to clarify that no, Microsoft doesn't secretly slurp your private repos through a side door to OpenAI.
But the discussion missed something. Even if you never touch Grok Build, the same class of risk exists with every AI coding tool you install. The question isn't "is Grok doing something shady?" — it's "how do you verify what your tool actually sends?"
What the analysis found
Let's separate the findings from the drama. The researcher (cereblab) used mitmproxy to intercept all traffic from grok 0.2.93 on macOS, with a throwaway repo full of canary tokens — unique strings planted in files to trace exactly what leaked where. The results:
Channel A — Model turns (what the agent reads): When Grok reads a file, its full contents are transmitted to xAI in the POST body to/v1/responses, including any .env file it opens. No redaction. Your secrets are line noise to the LLM, but they leave your machine as plaintext.
Channel B — Repo snapshots (what the agent didn't read): Grok packages the entire repository — every tracked file plus full git history — and uploads it via POST /v1/storage to a Google Cloud Storage bucket called grok-code-session-traces. This is a separate channel from the model turns. In one test, the agent was told Reply exactly OK, do not read any files. A planted file never_read_canary.txt was still recovered verbatim from the uploaded git bundle.
Channel B scales. On a 12 GB repo of never-read random files, the model-turn channel moved 192 KB. The storage channel moved 5.1 GiB. That's a ~27,800× ratio — proving the upload is a whole-repo snapshot, not a cache of read files.
The opt-out doesn't work. Disabling "Improve the model" left trace_upload_enabled: true on the server side. The toggle was cosmetic.
Third-party telemetry too. Mixpanel (api.mixpanel.com/track) and a grok.com/_data/v1/events endpoint were also active — standard telemetry, but nothing about it was disclosed during setup.
None of this proves xAI trains on the data. What it proves is transmission, acceptance, and storage. And that's already a lot.
The real question: what does your tool send?
I want to pause on the outrage for a moment. Yes, uploading entire repos without consent is bad. Yes, a non-functional opt-out toggle is worse. But outrage is cheap and Grok is one tool among dozens. The useful response isn't a tweet — it's a verification habit.
Every AI coding CLI — Cursor, Claude Code, Windsurf, Aider, Cline, Copilot CLI — has access to your filesystem. Every one of them connects to remote servers. Every one of them could, in principle, do exactly what Grok Build did. The difference between "Grok uploads everything" and "your tool doesn't" is evidence, not trust. And evidence is something you can collect yourself.
How to verify your own tools
The researcher's method is reproducible and cheap. Here's the practical setup:
Step 1: Set up mitmproxy
# Install
brew install mitmproxy
# Generate CA certificate
mitmproxy --mode regular@8080
# Visit mitm.it in a browser and install the cert, or run:
security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db ~/.mitmproxy/mitmproxy-ca-cert.pem
On Linux, trust the CA at the system level (path varies by distro). On Windows, import mitmproxy-ca-cert.pem into the Trusted Root Certification Authorities store.
Step 2: Route the CLI through the proxy
HTTPS_PROXY=http://127.0.0.1:8080 SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem your-ai-cli --prompt "fix the lint warnings"
Step 3: Plant canary files
Create a test repo with unique markers you can grep for in captured traffic:
echo "API_KEY=CANARY-A1B2C3-SECRET-NEVER-LEAVE" > .env
echo "MARKER-X7K9P-unique-probe" > src/never-read-canary.txt
Then run the CLI with a prompt that does not reference those files. After the run, search your mitmproxy dump for the markers:
grep -r "CANARY-A1B2C3" ~/.mitmproxy/dumps/
If you find it, you know exactly what channel leaked it.
Step 4: Check for repo snapshots
Watch for large uploads to storage endpoints — anything in the tens or hundreds of megabytes that doesn't correspond to a prompt response. In the Grok case, these hit /v1/storage on the same host. Your tool might use a different pattern. Look for:
- Uploads to
storage.googleapis.com,s3.amazonaws.com, or*.blob.core.windows.net - Large POST bodies that don't match the size of your conversation
- Multipart upload chunks (multiple
PUTorPOSTcalls in rapid succession) - Any upload that continues after the model response is complete
Step 5: Check the binary
strings is your friend:
strings $(which your-ai-cli) | grep -iE 'upload|telemetry|analytics|track|collect|storage|bucket|gcs|s3'
The Grok binary contained lines like crates/codegen/xai-data-collector/src/gcs.rs, grok-code-session-traces, and "Uploading bytes to GCS via proxy". Your tool will have similar breadcrumbs if it does anything comparable.
What data boundaries actually matter
After you've verified what your tool sends, the next question is what should it send? Every AI coding tool needs at least some data to function — you can't get code suggestions without sharing code. The boundary isn't "zero data" — it's "what data, under what controls?"
Here's a framework for thinking about it:
1. Read scope vs. upload scope
Does the tool send only what it reads, or does it snapshot everything it could theoretically access? The Grok case is the worst pattern: it reads a .env you asked about and ships files you never mentioned. A well-designed tool sends only the files actually referenced in the current turn — the diff, not the repo.
2. Secrets redaction
Does the tool attempt to detect and strip secrets before transmission? Some do — GitHub Copilot has a secrets-scanning pipeline that blocks suggestions containing credentials before they leave your editor. Others don't. The Grok CLI sent .env values verbatim with no filtering at all.
3. Opt-out fidelity
If the tool has a "data collection" or "improve the model" toggle, does it actually change behavior? Verify this at the wire level, not the UI level. The Grok toggle changed a UI checkbox; the server-side trace_upload_enabled flag stayed true regardless.
4. Retention and destination
Where does the data go, and for how long? The Grok CLI sends to grok-code-session-traces on GCS. Where does your tool's data land? Is the bucket named in the binary? Can you find a retention policy in the documentation?
5. Git history
Does the upload include your commit messages, author metadata, and full DAG? The Grok CLI shipped the entire git bundle — history and all. For many teams, commit messages contain internal context, issue tracker references, and sometimes accidentally-committed secrets from earlier in the repo's life.
Check: If you recover an uploaded bundle (some tools stage uploads to a temp directory — grep forupload_queue or similar), run git log on it. Is your history there?
A practical security checklist
If your team is evaluating or already using an AI coding CLI, here's what to do before — or if you're already using one, right now:
Before adopting any AI coding CLI
- [ ] Sandbox it. Run the tool in a container, a VM, or at minimum with restricted filesystem access (bubblewrap on Linux, App Sandbox on macOS). Give it access only to the project directory, and make
.gitread-only or hidden. - [ ] Network-isolate it. Use a firewall or proxy to restrict outbound connections to only the API hostnames the tool needs to function. Block its own telemetry domains.
- [ ] Wire-verify it. Run it through mitmproxy on a throwaway repo with canary tokens. Check what leaves.
- [ ] Read the binary.
stringsthe executable. Look for upload paths, bucket names, telemetry endpoints. - [ ] Audit the settings. Check every configuration flag, environment variable, and config file. Look for data-sharing defaults. Toggle them all and re-verify on the wire.
- [ ] Assume
.envleaks. Keep secrets out of files the tool can read. Use a secrets manager with an API (Vault, AWS Secrets Manager, 1Password CLI) and inject at runtime, outside the project directory. - [ ] Assume
.gitleaks. If the tool has filesystem access, it can read your git objects. A tool that uploads repos captures your full history. Don't keep secrets in git history. Rotate anything that might be there.
If you're already using one
- [ ] Run the wire audit now. Better late than never. Knowing is better than hoping.
- [ ] Rotate exposed secrets. If your
.envor config files contain production credentials that may have been uploaded, rotate them. Treat it like any other potential credential leak. - [ ] Check for data processing agreements. If you're on a team or enterprise plan, you may have contractual protections that individual users don't. Read them.
- [ ] Push for transparency from vendors. Ask for clear documentation on what data is collected, where it goes, how long it's kept, and whether it's used for training. If the answer is vague, that's your answer.
Don't let this be a Grok story
The easy reaction is to say "well, I don't use Grok Build" and move on. That misses the point entirely.
Every AI coding tool on your machine has the same technical capability. The difference between the tools you trust and the one in this story isn't architecture — it's one researcher with mitmproxy and a weekend.
Be your own researcher. It's a few hours of work for a permanent answer about what's leaving your machine. That's a good trade.
Sources and further reading:
- What xAI's Grok Build CLI Actually Sends to xAI — the original wire-level analysis
- Hacker News discussion — 114 comments, including a response from a GitHub Copilot engineer on private repo access
- mitmproxy — the interception tool used in the analysis
- amazing-sandbox — a bubblewrap-based sandboxing tool mentioned in the HN thread