# What xAI Grok Build CLI actually sends to xAI - a wire-level analysis (grok 0.2.93)

> Source: <https://gist.github.com/cereblab/dc9a40bc26120f4540e4e09b75ffb547>
> Published: 2026-07-10 02:13:12+00:00

Update — 2026-07-14:This is the original wire-level analysis (grok 0.2.93). Since publishing: xAI disabled the upload server-side (`disable_codebase_upload: true`

); added a`/privacy opt-out`

— which I wire-tested and found to be a data-retentionsetting, not a block on what'ssent; and Elon Musk publicly committed to deleting all previously-uploaded data (not yet confirmed complete). Full, maintained story + evidence:·[https://cereblab.com][https://github.com/cereblab/grok-build-exfil-repro]

*By @cereblab — Independent AI Safety Checker. Reproduce it yourself: github.com/cereblab/grok-build-exfil-repro*

*A measured, reproducible teardown. Findings are backed by captured artifacts (endpoint, HTTP method, status code, byte size, host) and repro commands; where an observation was seen live but not retained as a file, §7 says so explicitly. Section 8 is an evidence appendix with SHA-256s and a "what we did not prove" list. All captures are of my own traffic on my own machine, using a throwaway repository containing fake "canary" secrets — no real credentials were exposed.*

xAI's official **Grok Build** coding CLI (`grok`

), on a normal consumer login, does three things worth documenting precisely:

**It transmits the contents of files it reads — including a** The secret appears in`.env`

secrets file — to xAI, verbatim and unredacted.*two*channels: the live model turn (`POST /v1/responses`

) and a`session_state`

archive uploaded and**accepted (HTTP 200)** via`POST /v1/storage`

— the endpoint the binary routes to the`grok-code-session-traces`

GCS bucket (see §5).**It uploads the** Grok packages the workspace and uploads it via*whole repository*— every tracked file's content plus git history — independent of what the agent reads.`POST /v1/storage`

. Proven directly: on a real codebase, with the prompt*"reply OK, do not read any files"*, Grok uploaded the**entire repo as a git bundle**(`POST /v1/storage → 200`

);`git clone`

-ing the captured bundle recovers a file the agent was**told not to open**—`src/_probe/never_read_canary.txt`

— with its unique marker**verbatim**, plus the full git history (appendix`uploaded_repo.bundle`

). And it scales: on a**12 GB** repo of never-read random files,`/v1/storage`

moved**5.10 GiB, all HTTP 200**(truncated mid-stream), while the model-turn channel moved just** 192 KB**— a**~27,800× ratio** that pins the upload to the codebase, not to what was read. No storage upload failed; the only non-200s were a**model-usage quota**(402/429) on`/v1/responses`

and one unrelated 404 —*not*a storage size cap.**The storage destination is a Google Cloud Storage bucket,**(not AWS S3) — named verbatim in the binary and in a captured`grok-code-session-traces`

`metadata.json`

(`gs://grok-code-session-traces/…`

). I did not find this mechanism surfaced in the CLI's install/quickstart materials (not an exhaustive docs audit — §7), it is active by default, and**disabling "Improve the model" does not turn it off**(`/v1/settings`

still returned`trace_upload_enabled: true`

; §6).

None of this proves xAI *trains* on the data — that is a policy question addressed in §6. What is proven is transmission, acceptance, and storage.

```
Install:  curl -fsSL https://x.ai/cli/install.sh | bash      # → ~/.grok/bin/grok
Auth:     first launch opens a browser → login to X / SuperGrok (consumer account, not an API key)
```

Binary identity (repro: `file $(readlink -f ~/.grok/bin/grok); ~/.grok/bin/grok --version; shasum -a 256 $(readlink -f ~/.grok/bin/grok)`

):

``` php
~/.grok/bin/grok -> ../downloads/grok-macos-aarch64
Mach-O 64-bit executable arm64
grok 0.2.93 (f00f96316d4b)
SHA-256: 2a97ba675bd992aa9b981e2e83776460d94f469b510c0b8efe28b50d236d767c
```

The upload machinery is a first-party Rust crate. `strings`

on the binary yields these source paths and constants (repro: `strings <binary> | grep -E 'xai-data-collector|grok-code-session-traces|storage.googleapis'`

):

```
crates/codegen/xai-data-collector/src/gcs.rs
crates/codegen/xai-data-collector/src/storage_client.rs
crates/codegen/xai-data-collector/src/queue.rs
crates/codegen/xai-data-collector/src/file_access_tracker.rs
crates/codegen/xai-data-collector/src/circuit_breaker_observer.rs
crates/codegen/xai-grok-shell/src/upload/{gcs,turn,trace,manifest}.rs
grok-code-session-traces
storage.googleapis.com
"Uploading bytes to GCS via proxy"
```

Environment: macOS, Apple Silicon, `grok 0.2.93`

, July 2026.

`brew install mitmproxy`

; run once to generate its CA at`~/.mitmproxy/`

.- Trust the CA in the
**login** keychain (no sudo; Grok does not certificate-pin against it):

```
security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db \
  ~/.mitmproxy/mitmproxy-ca-cert.pem
```

- Run Grok routed through the proxy (a
`mitmdump`

addon logs, per request: method, host, path,**response status**, request byte size; and saves request bodies for xAI hosts):

```
HTTPS_PROXY=http://127.0.0.1:8080 SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem \
  grok -p "<prompt>" --cwd <repo>
```

- For staged-artifact inspection, race-copy
`~/.grok/upload_queue/*`

during the run, then`gzip -dc | tar -xO`

.

Canary repo: each file carries a unique marker so anything appearing in captured traffic is unambiguously traceable to a file. Secrets file `secrets.env`

/ `.env`

:

```
API_KEY=CANARY7F3A9-SECRET-should-not-leave
DB_PASSWORD=CANARY7F3A9-DBPASS
```

**Claim:** when Grok reads a file, its contents are transmitted to xAI — serialized into the `POST /v1/responses`

model-turn body, and packaged into a `session_state`

archive that is uploaded and **accepted (HTTP 200)** via `POST /v1/storage`

— with no redaction of the file's contents. A `.env`

is sent like any other file.

**Wire artifact** — a decrypted 48,070-byte `POST cli-chat-proxy.grok.com/v1/responses`

request body (identifiable as a model turn by its embedded `"messages":[…]"model":"grok-4.5"`

JSON). It contains the secrets file **verbatim** (appendix: `secrets_responses_body.bin`

, `secret_verbatim.txt`

):

```
…API_KEY=CANARY7F3A9-SECRET-should-not-leave\nDB_PASSWORD=CANARY7F3A9-DBPASS\n…"model":"grok-4.5"…
```

**Repro:** `grep -a "CANARY7F3A9-DBPASS" secrets_responses_body.bin`

→ matches. All six file markers (source, logic, README, nested JS, API key, DB password) are recoverable from the decrypted `/v1/responses`

bodies. (This artifact proves the secret was **transmitted** to the `/v1/responses`

endpoint; the raw body file does not carry the response status, so the **acceptance (200)** claim is anchored to the `/v1/storage`

channel immediately below, which is status-mapped in `wire_12gb.log`

.)

**Second channel — persisted to Google Cloud Storage.** The same content is packaged into a `session_state`

archive uploaded via `POST /v1/storage`

. Proven by decompressing the staged artifact before it drains (appendix: `secrets_session_state.tar.gz`

):

```
gzip -dc secrets_session_state.tar.gz | tar -xO | grep -ao 'CANARY7F3A9-[A-Z]*'
→ CANARY7F3A9-SECRET, CANARY7F3A9-DBPASS, + all others
```

So the secret is not only processed in-flight; it is written into an archive destined for storage.

**Pre-empting "you told it to read the secrets."** A control run with a file the agent was told **not** to open (`untouched_secret.txt`

) and the prompt *"Reply exactly OK, do not read any files"* produced **no** occurrence of that file's marker in any captured body. The leak is therefore scoped to files Grok **does** read — but it reads liberally (any file relevant to the task, including a `.env`

) and applied **no** redaction to that file's contents. The defect is that a secrets file was transmitted unredacted, not the act of reading. **Important scope reconciliation:** this control shows the unread file is absent from the ** /v1/responses** bodies — that is

*Channel A*(files the agent reads). It does

**not** clear the separate whole-repo

**snapshot in §4 (**

`/v1/storage`

*Channel B*), which — by the volume evidence there — does sweep in never-read files; I could not decompress the

`/v1/storage`

codebase chunk to check this specific file. So "unread file not uploaded" is true **only for the model-turn channel**, not for the codebase snapshot. (Two further scope notes: (i) in my runs the

`.env`

/`secrets.env`

was git-tracked; I did not separately test whether a `.gitignore`

d file is still uploaded, so I make no gitignore claim — the mechanism is read-driven per the `file_access_tracker`

crate, but that specific case is untested. (ii) The canary values sat in `API_KEY=`

/`DB_PASSWORD=`

keys inside a `.env`

/`secrets.env`

but were not real-format high-entropy tokens; I proved *this*, not that no redactor exists for, say, an

`.env`

was transmitted unredacted`sk-…`

-shaped key.)## 4. Finding 2 — The whole repo is uploaded at multi-GB scale; the only ceiling is a model quota, not storage size

**Claim:** Grok uploads a whole-repo snapshot with no storage size wall in the tested range. As the repo grows it switches upload strategy and keeps returning 200; on a 12 GB repo, 73 chunks of ~75.0 MB (5.10 GiB) uploaded with zero failures before the capture was truncated mid-stream.

Wire-captured size sweep (incompressible content so the tar cannot shrink; fresh session each step). **Only the 12 GB row was retained as a file** (`wire_12gb.log`

); the smaller rows were observed live during the sweep but their logs were not saved (see §7):

| Repo size | Upload behavior (observed on the wire) | Status | Artifact |
|---|---|---|---|
| 64 MB | single `POST /v1/storage` , `req=50548145b` (48 MB) |
200 |
observed, not retained |
| ~600 MB | `POST /v1/storage` in ~7.5 MB chunks (dozens) |
all 200 |
observed, not retained |
| ~3 GB | `POST /v1/storage/multipart/init` → `PUT storage.googleapis.com/grok-code-session-traces/multipart/<id>` in 50 MB parts (direct-GCS PUT lines not preserved — §7) |
all 200 |
observed, not retained |
| ~12 GB | `POST /v1/storage` in 75 MB chunks (`req≈75014840b` ); 73 chunks (~5.1 GB) captured before I stopped the run |
all 200, 0 failures |
`wire_12gb.log` |

**Preserved artifact:** `wire_12gb.log`

(appendix). It contains **83 /v1/storage* 200 responses**:

**82** content-upload

`POST …/v1/storage`

requests — of which **73 are chunks of ~75.0 MB each**(byte sizes min 75,014,811 / max 75,014,871, totaling

**5,476,083,317 B = 5.10 GiB / 5.48 GB**) plus

**9** smaller POSTs — and

**1**

`/v1/storage/batch_exists`

dedup check. Total `/v1/storage*`

request bytes: 5,476,228,005 B. **Zero** storage requests failed. The capture was stopped while uploads were still streaming (the last line is another ~75 MB chunk → 200), so this demonstrates

**≥5.1 GiB uploaded, still climbing when truncated**—

*not*that the full 12 GB completed. Repro (three greps, so no count is ambiguous):

`grep 'cli-chat-proxy.grok.com/v1/storage' wire_12gb.log | grep -c '> 200'`

→ **83**(all

`/v1/storage*`

); `grep 'POST cli-chat-proxy.grok.com/v1/storage ' wire_12gb.log | grep -c '> 200'`

→ **82**(content POSTs only);

`grep req=75014 wire_12gb.log | grep -c '> 200'`

→ **73**(the ~75 MB chunks).

**Scope — this is the whole repo, not just files the agent read.** Channel A (§3,

`/v1/responses`

) carries files the agent opens. This §4 upload is a separate **Channel B**: a snapshot of the entire workspace. Two lines of evidence:

**(a) The decisive byte split (load-bearing).** In the*same*captured 12 GB session — a repo of**100 % random files the agent never read**— the two channels moved wildly different volumes:** Channel A**, across 5 requests, largest single turn 60,394 B.`/v1/responses`

(model turns): 196,705 B = 192 KB total**Channel B**`/v1/storage`

: 5,476,228,005 B = 5.10 GiB.- That is a
**~27,800× ratio**(5,476,083,317 ÷ 196,705). The model** demonstrably never ingested the files**(192 KB cannot carry 5 GiB of content), yet 5.10 GiB of them left via`/v1/storage`

— and across the sweep the`/v1/storage`

volume**tracks total repo size**(64 MB → 12 GB). GB-scale bytes leaving a never-read repo can only be a whole-repo snapshot.

**(b) The binary's own paths/strings** corroborate the mechanism:`after_codebase.tar.gz`

,`xai-grok-shell/src/upload/{trace,turn}.rs`

,`repo_state.upload`

,*"collecting workspace files"*,*"spawning background coordinator"*.**(c) A staged codebase manifest enumerates a never-read file and content-addresses it to the GCS bucket.** In a separate run on a**real 298-file**, I race-copied the snapshot Grok staged for upload (appendix:`cereblab_api`

codebase`staged_base_tree_manifest.json`

,`staged_metadata.json`

). The manifest lists— a file I planted and never asked Grok to open — alongside the real sources (`src/_probe/never_read_canary.txt`

`src/apns.ts`

,`src/index.ts`

, …); and`metadata.json`

gives each file a destination`fileId`

of the form. So the whole tree, unread files included, is enumerated and content-addressed for upload to the named GCS bucket. (That run was quota-blocked before the content blobs uploaded; the 12 GB run above independently proves`gs://grok-code-session-traces/repo_changes_dedup/v2/supplemental/sha256_…`

*GB-scale content actually leaves the wire, all 200*.)**(d) DEFINITIVE — a never-read file's** With the account upgraded (quota lifted), I re-ran on the real*content*recovered verbatim from an uploaded git bundle (single SuperGrok run).`cereblab_api`

repo with the explicit prompt`Reply with exactly: OK. Do not read or open any files.`

, having planted a unique marker`CANARY-XR47P2-NEVERREAD-UNIQUE`

in`src/_probe/never_read_canary.txt`

. Grok uploaded the**entire repository as a git bundle** via`POST cli-chat-proxy.grok.com/v1/storage → 200 (req=152102b)`

(appendix`uploaded_repo.bundle`

, SHA-256`73b9c0af06311bae35c3ed03274d0eec2846e76762828d10b09757ca41bd6024`

). Running`git clone uploaded_repo.bundle`

reconstructs the repo, and`src/_probe/never_read_canary.txt`

contains the marker**verbatim**— a file the agent was explicitly told not to open. The bundle also carries the** full git history**(4 commits, 47 files). This is the airtight per-file-content proof: the whole repo — unread files included — left the machine and was accepted (200). The upload mechanism is a**git bundle**, so "whole repo" is literal (every tracked file + history).** Replicated on a second, unrelated codebase:**the identical capture on the`cereblab_auth`

Cloudflare-Worker repo produced a git-bundle upload (`POST /v1/storage → 200`

, 31,743 B) from which`git clone`

recovered its own never-read marker`CANARY-AUTH-4T8K2-NEVERREAD`

verbatim (appendix`uploaded_repo_auth.bundle`

, SHA-256`0ee536538bcd1ee72a258f9977ab69f8a9b1ac240491b91a4e94335b4d83c768`

). Two independent repos, same result.

*(Prompt note: the 12 GB session was interactive and I did not log its verbatim prompt, but the 192 KB Channel-A total is dispositive that no bulk read occurred whatever the prompt was; a separate headless control run used the explicit prompt Reply exactly OK, do not read any files and confirmed an unread file is absent from Channel A.)*

*(The earlier "one gap" is now closed by evidence (d): a single SuperGrok run where a specific never-read file's content is recovered from a wire-captured, 200-status git-bundle upload. The 12 GB run remains the proof that this scales to GB volumes.)*

**No storage/upload request failed — every one of the 82 /v1/storage calls returned 200.** The only non-200s in the entire capture were on the model endpoint plus one session-bookkeeping call (full set from

`wire_12gb.log`

; `/v1/responses`

lines also in `model_limit.txt`

):

``` php
POST /v1/responses                     -> 402   (Payment Required)   ×1
POST /v1/responses                     -> 429   (Too Many Requests)  ×3
POST /v1/sessions/<id>/replicas/update -> 404                        ×1   (session bookkeeping, not an upload)
```

and finally, in plain text, on stdout:

```
You've reached your free Grok Build usage limit for now. Get SuperGrok for much higher limits…
```

The 402/429 are a **model-usage quota**; the lone 404 is unrelated to storage. Notably, storage uploads continued to return 200 *after* the model turn was rate-limited (76 `/v1/storage`

200s occur at or after the first 429) — the codebase upload is independent of whether the model answers.

**Pre-empting "you're confusing a local disk cache with an upload."** This claim rests strictly on **wire-captured 200-status uploads** of file bytes leaving the machine (`/v1/storage`

request bodies of 7.5–75 MB in the preserved `wire_12gb.log`

; the 3 GB 50 MB `PUT`

s to `storage.googleapis.com`

were also seen on the wire, but that log was not retained — §7). It does **not** rely on the `~/.grok/upload_queue`

draining — queue-drain is ambiguous (it empties on both success and drop) and is explicitly **not** used as evidence here. (An earlier draft that inferred upload from queue-drain was wrong and has been retracted; see §7.)

**Storage destination is Google Cloud Storage**, bucket. This rests on the`grok-code-session-traces`

**preserved** binary strings`grok-code-session-traces`

,`storage.googleapis.com`

, and*"Uploading bytes to GCS via proxy"*(`crate_strings.txt`

),**and on a preserved staged**(`metadata.json`

whose per-file`fileId`

s are literally`gs://grok-code-session-traces/repo_changes_dedup/v2/…/sha256_…`

`staged_metadata.json`

), corroborated by the direct`storage.googleapis.com`

multipart PUTs observed at 3 GB (observed live; that log was not retained — see §7). It is**not** AWS S3 (the binary links`aws-sdk-s3`

for an alternate path and AWS STS/SSO for auth, but the destination named in the binary — and seen on the wire at 3 GB — is GCS).**Third-party telemetry:**`POST api.mixpanel.com/track`

and`/engage`

(Mixpanel), plus`POST grok.com/_data/v1/events`

— all 200.**Not surfaced in setup docs (scope-limited claim):** I did not find the`repo_state`

/`session_state`

upload to`grok-code-session-traces`

, or the`~/.grok/upload_queue`

staging, described in the CLI's install script or quickstart materials I reviewed (this is not an exhaustive audit of all xAI docs — see §7). The mechanism is active by default on the standard consumer login.**Reliability note (separate from privacy):**`~/.grok/upload_queue`

stages ~3 GB snapshots per turn and, under load, can grow to tens of GB and exhaust the disk. This is a real bug, independent of whether uploads succeed.

**"Cloud AI tools send context; this is normal."** True, and conceded: any cloud coding agent must send code to its server to act on it. The**novel deltas** here are (a) a**secrets** file (e.g.`.env`

) is transmitted**unredacted**, (b) the content is** persisted**to a named GCS bucket, not just processed transiently, and (c) the upload mechanism is** not surfaced in the CLI's setup materials**(§7) and on by default.**"It's in the ToS / opt-in."** xAI's consumer policy broadly discloses data use for model improvement with an opt-out (grok.com → Settings → Data → "Improve the model"; Private Chat auto-opts-out; opt-out is prospective, not retroactive). But**broad training disclosure ≠ documenting this specific mechanism.** I did not find the`repo_state`

/`upload_queue`

/`grok-code-session-traces`

pipeline described in the CLI materials I reviewed (§7 notes this is not an exhaustive docs audit), so — on those materials — a user is not informed of*it*specifically. Sources: xAI Privacy Policy ([https://x.ai/legal/privacy-policy](https://x.ai/legal/privacy-policy)), Consumer ToS ([https://x.ai/legal/terms-of-service](https://x.ai/legal/terms-of-service)).**The "Improve the model" toggle makes no difference — ON or OFF, the whole repo is uploaded the same way.** At default settings, Grok uploaded 5.10 GiB of a never-read repo (§4). Then I**turned "Improve the model" off** and re-ran: Grok*still*uploaded the entire repo as a git bundle (§4(d),`POST /v1/storage → 200`

, the never-read file recovered by`git clone`

), and the server's`/v1/settings`

response to the CLI*still*returned`"trace_upload_enabled": true`

,`"upload_enabled": true`

,`"session_registry_enabled": true`

(and`"max_upload_file_bytes": 1073741824`

, a 1 GiB per-file cap). The opt-out governs**training**, not whether your code is uploaded/stored: the codebase upload to`grok-code-session-traces`

continues either way.**Opting out does not stop your repository from leaving the machine.**

**We did not prove xAI trains on this data.** Upload/storage ≠ training. That is governed by policy and account tier; we measured transmission only.**The direct**(the log was overwritten during the sweep, and re-capture is currently blocked by the model quota). The multi-GB claim in §4 therefore rests on the`storage.googleapis.com/grok-code-session-traces`

PUT wire-lines were observed at 3 GB but not preserved in this session**preserved**`wire_12gb.log`

(`/v1/storage`

200s at 75 MB chunks) plus the binary strings naming the bucket; the direct-PUT capture is reproducible once quota resets.**Only the 12 GB sweep log was retained.** The 64 MB / 600 MB / 3 GB rows were observed live but their capture logs were not saved (reproducible once quota resets). The 12 GB capture itself was stopped mid-stream (~5.1 GB / 73 chunks captured), so it proves multi-GB upload*succeeds with no failures*, not that an entire 12 GB repo run completes end-to-end.**The "not documented" claim is scope-limited.** I based it on the CLI's install script and quickstart, not an exhaustive search of all xAI documentation, help-center articles, or policies. It is possible the mechanism is described somewhere I did not check; the defensible statement is "not surfaced in the CLI's own setup materials."**Channel B (whole-repo) — now CLOSED (was the one open gap).** Evidence §4(d): on a SuperGrok account, a single run wire-captured Grok uploading the**entire repository as a git bundle** via`POST /v1/storage → 200`

;`git clone`

of the preserved`uploaded_repo.bundle`

recovers`src/_probe/never_read_canary.txt`

— a file the agent was told not to open — with its unique marker**verbatim**, plus the full git history. So the never-read file's*content*(not just its hash) demonstrably left the machine and was accepted. The`wire_12gb.log`

run remains the proof that the same mechanism scales to GB volumes.**Universal vs. conditional (partially answered):** multi-GB upload succeeds on free-tier; the git-bundle content upload succeeds on SuperGrok**with "Improve the model" turned OFF**(`/v1/settings`

returned`trace_upload_enabled: true`

). I did**not** find a setting that disables the upload in these tests, but I did not exhaustively enumerate every account/config permutation, so I don't claim it can*never*be gated.**One earlier claim was retracted:** an initial "the multi-GB blobs fail and are deleted locally, not exfiltrated" conclusion — based on a**PID-scoped**`nettop`

reading (<1 MB) — was wrong. PID/host-scoped egress misses (a) a separate upload coordinator process and (b) presigned`PUT`

s that go**directly to Google IPs**, never touching the API host. The wire capture (this document) supersedes that inference.

All artifacts and SHA-256s (`MANIFEST.sha256`

). Binary SHA-256: `2a97ba675bd992aa9b981e2e83776460d94f469b510c0b8efe28b50d236d767c`

.

| Artifact | What it proves |
|---|---|
`secrets_responses_body.bin` (48 KB) |
`.env` contents verbatim in a `POST /v1/responses` body |
`secret_verbatim.txt` |
the two `.env` lines as extracted |
`secrets_session_state.tar.gz` (16 KB) |
same secret inside the archive uploaded via `/v1/storage` |
`wire_12gb.log` |
83 `/v1/storage*` → 200 on a 12 GB repo = 82 content POSTs (73 chunks ~75.0 MB = 5.10 GiB + 9 small) + 1 `batch_exists` ; Channel-A `/v1/responses` = 196,705 B (192 KB) total (~27,800× less); 0 storage failures; truncated mid-stream |
`model_limit.txt` |
the `/v1/responses` failures (402×1, 429×3 — model quota) |
`crate_strings.txt` |
`xai-data-collector` paths + `grok-code-session-traces` + `storage.googleapis.com` |
`binary.sha256` |
binary provenance |
`gcs_puts.txt` |
placeholder (empty capture) — the 3 GB direct-GCS PUT lines were not retained; note inside explains, re-capture pending quota (§7) |
`uploaded_repo.bundle` (152 KB, SHA-256 `73b9c0af…` ) |
the smoking gun — a git bundle wire-captured leaving via `POST /v1/storage → 200` ; `git clone` recovers `src/_probe/never_read_canary.txt` (never-read) verbatim + full git history (real `cereblab_api` repo, SuperGrok, "Improve the model" OFF) |
`uploaded_repo_auth.bundle` (SHA-256 `0ee53653…` ) |
replication on a 2nd unrelated repo (`cereblab_auth` Worker) — git bundle via `POST /v1/storage → 200` ; `git clone` recovers its never-read canary `CANARY-AUTH-4T8K2-NEVERREAD` verbatim |
`staged_base_tree_manifest.json` |
real-code run: the codebase snapshot manifest enumerating (never-read) + 30 real `src/_probe/never_read_canary.txt` `src/*.ts` files |
`staged_metadata.json` |
real-code run: per-file destinations `fileId: gs://grok-code-session-traces/repo_changes_dedup/v2/…/sha256_…` (names the GCS bucket) |

**Repro (condensed):**

```
brew install mitmproxy && mitmdump -q -p 8080   # generates ~/.mitmproxy CA
security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db ~/.mitmproxy/mitmproxy-ca-cert.pem
# capture a run:
HTTPS_PROXY=http://127.0.0.1:8080 SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem grok -p "read every file" --cwd <repo>
# secrets: grep -a CANARY <saved /v1/responses body>
# staged:  gzip -dc <staged session_state> | tar -xO | grep CANARY
```

**Integrity:** all captures were of my own traffic on my own machine; the "secrets" were fake canary strings; no real credentials were exposed. Findings are version-specific to `grok 0.2.93`

(July 2026); xAI may change behavior at any time.
