xAI Grok Build CLI のデータ送信実態
本文の状態
日本語全文を表示中
詳細モードで約33分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
TLDR AI
xAI のコーディング CLI「Grok Build」が、ユーザーの機密情報を含むファイル内容やリポジトリ全体を、明示的な同意なくサーバーへ送信する実態が分析され、セキュリティ上の重大な懸念が浮上した。
AI深層分析を開く2026年8月2日 14:52
AI深層分析
キーポイント
機密情報の無修正転送
CLI が読み込んだファイルの内容(.env ファイルなどのシークレット含む)を、非表示化や匿名化処理を行わずに xAI サーバーへ送信する挙動が確認された。
リポジトリ全体のアップロード
エージェントが特定のファイルのみを読み込むよう指示した場合でも、ワークスペース内の全 tracked ファイルと git 履歴をパッケージ化してアップロードする仕組みが存在した。
プライバシーオプトアウトの限界
追加された「/privacy opt-out」コマンドがデータ転送そのものをブロックする機能ではなく、単にサーバー側でのデータ保持期間を調整する設定であることが分析で判明した。
独立系調査による実証
独立系の AI セーフティチェッカーが、架空の秘密鍵(canary)を用いたテスト環境でトラフィックをキャプチャし、HTTP 200 ステータスでのアップロード成功を実証した。
.env ファイルを含むファイル内容の送信
Grok Build CLI は、.env シークレットファイルを含む読み込んだファイルの内容を、未編集のまま xAI に送信する。この情報は生モデル通信とセッション状態アーカイブの両方で送信され、HTTP 200 で受け入れられる。
重要な引用
It transmits the contents of files it reads — including a .env secrets file — to xAI, verbatim and unredacted.
It uploads the whole repository — every tracked file's content plus git history — independent of what the agent reads.
added a /privacy opt-out — which I wire-tested and found to be a data-retention setting, not a block on what's sent
"It transmits the contents of files it reads — including a .env secrets file — to xAI, verbatim and unredacted."
編集コメントを表示
編集コメント
本分析は、AI ツールの利便性とデータセキュリティのバランスが崩れている現状を浮き彫りにする。開発者はツールの機能だけでなく、背後でどのようなデータ処理が行われているかを常に疑う姿勢を持つ必要がある。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
xAI Grok Build CLI が xAI へ実際に送信するデータの詳細分析(Grok 0.2.93)
更新 — 2026-07-14: これはオリジナルのワイヤーレベル分析(grok 0.2.93)です。公開後、xAI はサーバー側でのアップロードを無効化しました(
disable_codebase_upload: true)。また/privacy opt-outを追加しましたが、これは私がワイヤーテストした結果、送信されるデータそのものをブロックするものではなく、データの保持期間に関する設定であることが判明しました。さらにイーロン・マスク氏は、過去にアップロードされたすべてのデータを削除すると公約しましたが、完了は未確認です。
完全なストーリーと証拠については、以下のリンクをご参照ください:https://cereblab.com · https://github.com/cereblab/grok-build-exfil-repro
*著者:@cereblab — 独立系 AI セーフティチェッカー。ご自身でも再現可能です:github.com/cereblab/grok-build-exfil-repro*
*これは計測可能で再現性の高い分析です。発見された事実は、キャプチャされたアーティファクト(エンドポイント、HTTP メソッド、ステータスコード、バイトサイズ、ホスト)と再現可能なコマンドによって裏付けられています。生で確認したがファイルとして保存しなかった観測については、§7 で明示的に記載しています。セクション 8 は証拠の付録であり、SHA-256 ハッシュ値や「証明できなかったこと」の一覧が含まれています。すべてのキャプチャは、私自身のネットワークとマシン上で、偽の「カニオン(canary)」シークレットを含む使い捨てリポジトリを用いて取得したものです。実際の認証情報は一切漏洩していません。
0. まとめ
xAI の公式コーディング CLI Grok Build(grok)は、通常の一般ユーザーのログインにおいて、正確に文書化する価値のある 3 つの動作を行います:
このツールは、読み込んだファイルの内容をそのまま xAI へ送信します。.env シークレットファイルも例外ではありません。シークレット情報は、ライブモデルの応答(POST /v1/responses)と、アップロードされる session_state アーカイブという *2 つ* の経路で送信されます。
そして、HTTP 200(成功)として受け入れられ、POST /v1/storage エンドポイントを経由して転送されます。このエンドポイントは、バイナリが grok-code-session-traces GCS バケットへルーティングする先です(§5 を参照)。
このツールは、エージェントが読み込むファイルに関係なく、リポジトリ全体(すべての追跡済みファイルの内容と Git の履歴)をアップロードします。Grok はワークスペースをパッケージ化し、POST /v1/storage を経由して転送します。実証済みの事実として、実際のコードベースで「OK と返信し、どのファイルも読まないで」というプロンプトを実行した際にも、Grok はリポジトリ全体を 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、および完全な Git の履歴(付録:uploaded_repo.bundle)
スケーラビリティも証明されています。未読のランダムファイルで構成された 12 GB のリポジトリに対して /v1/storage を実行すると、5.10 GiB が転送され、すべて HTTP 200(成功)となりました(ストリーミング途中での出力は省略)。一方、モデル処理チャネルで転送されたのはわずか 192 KB に過ぎません。これは約 27,800 倍 の差であり、アップロードが「実際に読み込まれたデータ」ではなく「コードベース全体」に依存していることを示しています。
ストレージのアップロードで失敗した事案は一つもなく、HTTP ステータスコードが 200 でなかったのは /v1/responses におけるモデル利用枠の制限(402/429)と、関連性の低い 404 エラーただ一つのみです。これはストレージ容量の上限に達したことを意味するものではありません。
- 保存先は Google Cloud Storage バケット
grok-code-session-tracesです(AWS S3 ではありません)。この名前はバイナリ内およびキャプチャされたmetadata.json(gs://grok-code-session-traces/…) にそのまま記載されています。CLI のインストールやクイックスタート資料にはこの仕組みが明記されていませんでした(包括的なドキュメント監査を行ったわけではありませんが、§7 を参照)。デフォルトで有効になっており、「モデルの改善に利用する」機能を無効化しない限り動作します。
- The storage destination is a Google Cloud Storage bucket, grok-code-session-traces (not AWS S3) — named verbatim in the binary and in a captured 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
これをオフにするわけではありません(/v1/settings は依然として trace_upload_enabled: true を返しています;§6)。
これらはすべて、xAI がデータを学習していることを証明するものではありません。これは §6 で扱われるポリシー上の問題です。証明されているのは、データの送信、受領、保存という事実だけです。
1. 試験対象(出所)
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)
バイナリの身元確認(再現手順:file $(readlink -f ~/.grok/bin/grok); ~/.grok/bin/grok --version; shasum -a 256 $(readlink -f ~/.grok/bin/grok)):
~/.grok/bin/grok -> ../downloads/grok-macos-aarch64
Mach-O 64-bit executable arm64
grok 0.2.93 (f00f96316d4b)
SHA-256: 2a97ba675bd992aa9b981e2e83776460d94f469b510c0b8efe28b50d236d767c
アップロード機能は、xAI が自社開発した Rust クレートで実装されています。このバイナリに strings コマンドを適用すると、以下のソースパスや定数が抽出されます(再現手順: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"
2. 手法(再現可能)
環境:macOS、Apple Silicon、grok 0.2.93、2026 年 7 月。
brew install mitmproxyを実行し、一度だけ CA を生成します。CA の保存先は~/.mitmproxy/です。
- ログインキーチェーンにこの CA を信頼設定してください(sudo は不要です)。Grok はこの CA に対して証明書のピン留めを行っていません。
security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db \
~/.mitmproxy/mitmproxy-ca-cert.pem
- Grok をプロキシ経由で実行すると、リクエストごとに
mitmdumpアドオンがログを出力します(メソッド、ホスト、パス、レスポンスステータス、リクエストバイトサイズ)。また、xAI ホストへのリクエスト本文も保存されます。
HTTPS_PROXY=http://127.0.0.1:8080 SSL_CERT_FILE=~/.mitmproxy/mitmproxy-ca-cert.pem \
grok -p "<prompt>" --cwd <repo>
- 段階的なアーティファクトの検査を行う場合は、実行中に
~/.grok/upload_queue/*を競合コピーし、その後gzip -dc | tar -xOで展開してください。
Canary リポジトリ:各ファイルには一意のマーカーが含まれており、キャプチャされたトラフィックに現れるものはすべて、どのファイルから来たのかを明確に追跡できます。シークレットファイル secrets.env / .env:
API_KEY=CANARY7F3A9-SECRET-should-not-leave
DB_PASSWORD=CANARY7F3A9-DBPASS
3. 発見事項 1 — ファイルの内容(シークレットファイルを含む)が送信され、受け入れられる(200)
主張: Grok がファイルを読み込む際、その内容は xAI へ送信されます。具体的には、POST /v1/responses モデル・トーン本体にシリアライズされ、アップロードされて**受け入れられる(HTTP (原文の技術表記: session_state)
200) を経由して POST /v1/storage へ送信されます。ファイルの内容は一切隠蔽されません。.env ファイルも他のファイルと同様に送信されます。
ワイヤーアーティファクト — 復号化された 48,070 バイトの POST cli-chat-proxy.grok.com/v1/responses リクエスト本文(モデルのターンであることを示す以下の要素で識別可能)
埋め込まれた "messages":[…]","model":"grok-4.5" の JSON 形式です。 (原文の技術表記: "messages":[…]"model":"grok-4.5")
このファイルには、秘密鍵の情報がそのまま含まれています(付録:secrets_responses_body.bin、secret_verbatim.txt)。
…API_KEY=CANARY7F3A9-SECRET-should-not-leave\nDB_PASSWORD=CANARY7F3A9-DBPASS\n…"model":"grok-4.5"…
再現: grep -a "CANARY7F3A9-DBPASS" secrets_responses_body.bin を実行すると一致が検出されました。復号化された /v1/responses の本文から、ソースコード、ロジック、README、ネストされた JS、API キー、データベースパスワードの 6 つのファイルマーカーすべてを復元可能です。
このアーティファクトは、秘密が /v1/responses エンドポイントへ送信されたことを証明するものです。生データファイルにはレスポンスステータスが含まれていないため、200 番の成功(acceptance)という主張は、直下の /v1/storage チャンネルに根拠を置いています。これはステータスマッピングが行われています。
wire_12gb.log)。
第 2 のチャネル — Google Cloud Storage に永続化。 同じ内容は、session_state アーカイブとしてパッケージ化され、POST /v1/storage を経由してアップロードされます。
ステージされたアーティファクトを排出前にデコンプレッションすることで実証済み(付録: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
つまり、機密情報は転送中だけでなく、保存先となるアーカイブにも書き込まれているのです。
「秘密を読めと指示した」という批判への先回り対応
エージェントに開くなと指示されたファイル(untouched_secret.txt)を用いた対照実験では、プロンプトとして「OK とだけ返信し、どのファイルも読まないでください」を指定しました。その結果、キャプチャしたレスポンス本文のいずれにも、該当ファイルのマーカーは出現しませんでした。
つまり、情報の漏洩が起きたのは Grok が実際に読むファイルに限定されます。ただし、Grok はタスクに関連するあらゆるファイル(.env ファイルを含む)を広く読み込みます。そして、そのファイルの内容に対して何らかの赤塗り処理(redaction)は行われませんでした。
問題の本質は「秘密保持用のファイルが赤塗りされずに送信された」点にあり、「ファイルを読んだ行為」自体にあるわけではありません。重要な範囲の再確認:この対照実験により、エージェントが読まなかったファイルは /v1/responses 本文に含まれていないことが示されました。これは *Channel A*(エージェントが読むファイル)の話です。
なお、§4(Channel B)で言及されている別個の全リポジトリ/v1/storageスナップショットはクリアされません。同セクションのボリューム証拠から判断すると、このスナップショットには未読ファイルも含まれてしまいます。私は /v1/storage のコードベースチャンクを解凍して特定のファイルを確認することはできませんでした。したがって、「未読ファイルがアップロードされない」というのは、モデルターンチャネルに限った話であり、コードベースのスナップショットには当てはまりません。
(2 つの追加的な範囲に関する注記:(i) 私の環境では、.env/secrets.env が Git によって追跡されていました。.gitignore で除外されたファイルが依然としてアップロードされるかどうかは別途テストしていないため、Git ignore の有無については一切言及しません。)
このメカニズムは、file_access_tracker クレートに基づいてファイルアクセス駆動型で動作しますが、この特定のケースについては未検証です。
(ii)キャナリー値は、.env または secrets.env ファイル内の API_KEY= や DB_PASSWORD= キーに格納されていましたが、実際の形式を持つ高エントロピートークンではありませんでした。私はこの .env が...
送信されるのは、赤文字処理(リダクション)が施されていないデータです。ただし、例えば特定のケースで赤文字処理を行う仕組みが存在しないわけではありません。
「sk-…」という形状のキー。)
4. 発見事項2 — リポジトリ全体が数ギガバイト規模でアップロードされる;上限はストレージ容量ではなく、モデルの利用枠のみである
主張:Grok は、テスト範囲内のストレージ容量の制限なく、リポジトリ全体のスナップショットをアップロードします。リポジトリが大きくなるとアップロード戦略が切り替わり、常に 200 ステータスを返します。12 GB のリポジトリでは、約 75.0 MB(5.10 GiB)のチャンクが 73 個、キャプチャがストリーミング途中で打ち切られるまで失敗ゼロでアップロードされました。
ワイヤーキャプチャによるサイズスイープ(圧縮不可能なコンテンツのため tar ファイルが縮小せず、各ステップで新規セッションを使用)。12 GB の行のみがファイルとして保持されました (wire_12gb.log)。それより小さい行はスイープ中にライブで観測しましたが、ログは保存していません (7 節参照)。
| リポジトリサイズ | アップロード動作(ネットワーク上で観測) | ステータス | アーティファクト |
|---|---|---|---|
| 64 MB | POST /v1/storage 単一リクエスト、req=50548145b (48 MB) | 200 | 観測済みだが保持されていない |
| ~600 MB | POST /v1/storage を約 7.5 MB チャンクで数十回実行 | すべて 200 | 観測済みだが保持されていない |
| ~3 GB | POST /v1/storage/multipart/init → PUT storage.googleapis.com/grok-code-session-traces/multipart/<id> を 50 MB パートで実行(直接 GCS PUT の行は保持されない — §7) | すべて 200 | 観測済みだが保持されていない |
| ~12 GB | POST /v1/storage を 75 MB チャンクで実行(req≈75014840b);停止する前に 73 チャンク(約 5.1 GB)をキャプチャ | すべて 200、失敗なし | wire_12gb.log |
保存されたアーティファクト: wire_12gb.log(付録)。このファイルには 83 件の /v1/storage* に対する 200 レスポンス が含まれています。そのうち 82 件は、コンテンツアップロード用の POST …/v1/storage リクエスト です。さらに詳しく見ると、これら 73 件が約 75.0 MB のチャンクデータ で構成されており、バイトサイズは最小 75,014,811 から最大までとなっています。
合計 75,014,871 で、5,476,083,317 B = 5.10 GiB / 5.48 GB に達し、さらに 9 の小規模な POST と、1 つの /v1/storage/batch_exists デュプリケーションチェックが行われました。
合計 /v1/storage* リクエストのバイト数は 5,476,228,005 B です。ストレージリクエストで失敗したのはゼロです。キャプチャはアップロードがまだストリーミング中(最後の行はさらに約 75 MB のチャンク→200)に停止されたため、これは「12 GB がすべて完了した」ことを意味するのではなく、「少なくとも 5.1 GiB がアップロードされ、切り捨てられる時点でまだ増加し続けていた」ことを示しています。
再現性確認(grep を 3 回実行し、カウントの曖昧さを排除): grep 'cli-chat-proxy.grok.com/v1/storage' wire_12gb.log | grep -c '> 200' → 83 (すべての /v1/storage* エンドポイント)
grep 'POST cli-chat-proxy.grok.com/v1/storage ' wire_12gb.log | grep -c '> 200'→ 82(コンテンツ送信のみ);
grep req=75014 wire_12gb.log | grep -c '> 200'→ 73(約 75 MB のデータを含むリクエスト) (原文の技術表記: grep 'POST cli-chat-proxy.grok.com/v1/storage ' wire_12gb.log | grep -c '> 200'、grep req=75014 wire_12gb.log | grep -c '> 200')
チャンク。
スコープ — これはエージェントが読み込んだファイルの一部ではなく、*リポジトリ全体*を指します。
チャンネル A(§3、/v1/responses)は、エージェントが開いたファイルを伝送する経路です。一方、この §4 のアップロードは別個のチャンネル Bであり、ワークスペース全体のスナップショットを送信しています。
その根拠となる証拠が 2 つあります:
(a)決定的なバイト分割(負荷の中心となる部分)。同じくキャプチャされた 12 GB のセッション内において、エージェントが一度も読んだことのない100% ランダムなファイルからなるリポジトリでさえ、2 つのチャンネルは劇的に異なる量のデータをやり取りしました。具体的には、Channel A /v1/responses(モデルの応答ターン)では 5 リクエストにわたって合計 196,705 バイト(約 192 KB)が送受信され、そのうち最大の単一ターンのサイズは 60,394 バイトでした。一方、Channel B /v1/storage では 5,476,228,005 バイト(約 5.10 GiB)ものデータが送られました。
これは約 27,800 倍の比率(5,476,083,317 ÷ 196,705)に相当します。モデルは明らかにファイルを読み込んでいません(192 KB で 5 GiB のコンテンツを担うことは不可能です)。にもかかわらず、5.10 GiB が /v1/storage を経由して流出しました。また、スweep(一連の調査)を通じて /v1/storage の使用量はリポジトリ全体のサイズと完全に一致しています(64 MB → 12 GB)。一度も読み込まれたことのないリポジトリからギガバイト単位のデータが流出している事実は、リポジトリ全体のスナップショットが取得されたことを意味します。
- (b) バイナリ自体に含まれるパスや文字列がその仕組みを裏付けています。具体的には
after_codebase.tar.gz、xai-grok-shell/src/upload/{trace,turn}.rs、repo_state.uploadというファイル名や、「ワークスペースのファイルを収集中」「バックグラウンドのコordinator を起動」といったログメッセージです。
- (c) 段階的に構築されたコードベースのリストは、一度も参照されていないファイルを列挙し、それを GCS バケットにコンテンツアドレスで保存します。 私は、実際の 298 ファイルからなる
cereblab_apiコードベース上で別の実行を行い、アップロードのために Grok がステージングしたスナップショットを競合コピーしました(付録:staged_base_tree_manifest.json、staged_metadata.json)。
マニフェストには、私が配置して一度も開くよう指示しなかったファイル src/_probe/never_read_canary.txt と、実際のソースコードが並んでいます。
src/apns.ts、src/index.ts などのファイルと、metadata.json が提供されます。
各ファイルは、gs://grok-code-session-traces/repo_changes_dedup/v2/supplemental/sha256_… という形式の宛先 fileId として扱われます。これにより、未読ファイルを含むツリー全体が列挙され、コンテンツアドレス化された上で、指定された GCS バケットへアップロードされます。(今回の実行は、コンテンツブロブのアップロード前にクォータ制限に抵触しましたが、上記の 12 GB の実行結果が独立して証明している通り、実際にギガバイト規模のデータがネットワークを通過し、すべて 200 件のファイルが含まれています。)
(d)決定版——未読ファイルの*内容*を、アップロードされた git バンドルから一字一句そのまま復元した結果(SuperGrok 1 回分の実行)。アカウントをアップグレードして制限を解除した後、実際の cereblab_api リポジトリで以下の明確なプロンプトを指定して再実行しました。
「OK」と正確に返信してください。ファイルの読み込みや開封は行わないでください。また、src/_probe/never_read_canary.txt 内に一意のマーカー CANARY-XR47P2-NEVERREAD-UNIQUE を埋め込んでいます。 (原文の技術表記: Reply with exactly: OK. Do not read or open any files.)
Grok は、リポジトリ全体を git bundle 形式でアップロードしました。送信先は POST cli-chat-proxy.grok.com/v1/storage で、レスポンスコードは 200(req=152102b)です。
添付ファイル:uploaded_repo.bundle
SHA-256: 73b9c0af06311bae35c3ed03274d0eec2846e76762828d10b09757ca41bd6024 (原文の技術表記: POST cli-chat-proxy.grok.com/v1/storage → 200 (req=152102b))
git clone uploaded_repo.bundle を実行するとリポジトリが復元され、src/_probe/never_read_canary.txt にはマーカーがそのままの形で含まれています。これはエージェントに対して開くなと明示的に指示されたファイルです。また、このバンドルには完全な git の履歴(4 つのコミット、47 ファイル)も含まれています。
これは、ファイルごとの内容に基づく厳密な証明です。未読のファイルを含め、リポジトリ全体がマシンから送信され、正常に受け入れられました(ステータスコード 200)。アップロード機構は git bundle を使用しているため、「リポジトリ全体」という表現は文字通りの意味を持ちます。つまり、追跡されているすべてのファイルと履歴が含まれます。
別の無関係なコードベースでも再現:cereblab_auth の Cloudflare Worker リポジトリで同じキャプチャを実行した結果、git-bundle アップロード(POST /v1/storage → 200、31,743 バイト)が発生し、そこから git clone で以前に読み込まれたことがないマーカーが復元されました。
CANARY-AUTH-4T8K2-NEVERREAD(付録 uploaded_repo_auth.bundle の厳密なコピー、SHA-256: 0ee536538bcd1ee72a258f9977ab69f8a9b1ac240491b91a4e94335b4d83c768)。
2 つの独立したリポジトリで、同じ結果が得られました。
(12GB のセッションは対話形式であり、その逐語的なプロンプトを記録していませんが、192KB の Channel-A 全体のデータから、どのようなプロンプトであったにせよ大量のファイル読み込みは行われていないことが確定しています。また、ヘッドレス環境での制御実験では「ファイルを一切読まずに『OK』とだけ返信する」という明示的なプロンプトを使用し、未読ファイルが Channel A に含まれていないことを確認しました。)
(以前の「1 つのギャップ」は、証拠 (d) によって埋められました。これは特定の一度も読み込まれたことのないファイルの内容が、ネットワーク経由でキャプチャされた 200 ステータスの git-bundle アップロードから復元された単一の SuperGrok の実行事例です。12GB の実行結果は、このスケーラビリティが GB オーダーのボリュームでも成り立つことを証明しています。) (原文の技術表記: Reply exactly OK, do not read any files)
ストレージやアップロードのリクエストは失敗していません。 82 回の /v1/storage 呼び出しすべてが 200 を返しました。キャプチャ全体で 200 以外だったのは、モデルエンドポイントとセッション管理の 1 件のみです(完全なセットは
wire_12gb.log; /v1/responses の行は model_limit.txt にも含まれています:
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)
そして最後に、標準出力には平文で以下が表示されます:
You've reached your free Grok Build usage limit for now. Get SuperGrok for much higher limits…
402 および 429 はモデル利用枠(クォータ)に関するエラーであり、唯一の 404 エラーはストレージとは無関係です。特筆すべき点として、モデル側の回答がレート制限に引っかかった後でも、ストレージへのアップロードは引き続き 200 OK を返していました。具体的には、最初の 429 エラーが発生した時点以降で、76 件の /v1/storage リクエストが 200 ステータスコードを返しています。これは、コードベースのアップロード処理が、モデルからの回答の有無とは独立して動作していることを示しています。
「ローカルディスクキャッシュとアップロードを混同している」という指摘への先回り。 この主張は、マシンから送出されるファイルバイトのワイヤーキャプチャされた 200 ステータスのアップロード(/v1/storage リクエストボディが 7.5〜75)に厳密に基づいています。
保存された wire_12gb.log に記録されている MB のうち、storage.googleapis.com 宛ての 3 GB 50 MB の PUT リクエストも確認されています。
ただし、このログは保持されていません(§7 参照)。また、~/.grok/upload_queue の排空にも依存していません。キューの排空は成功時と破棄時の両方で発生するため曖昧であり、ここでは証拠として明示的に使用されていないからです。
(キューの排水からアップロードを推測した以前の草案は誤りであり、撤回済みです。詳細は§7をご覧ください。)
5. 発見事項3 — 送信先、テレメトリ、ドキュメントに明記されていない情報
保存先は Google Cloud Storage のバケット grok-code-session-traces です。これは、バイナリ文字列として保持されている grok-code-session-traces、storage.googleapis.com、および「プロキシを介して GCS へバイトをアップロード中」というメッセージに基づいています。
crate_strings.txt および、各ファイルの fileId が実際に gs://grok-code-session-traces/repo_changes_dedup/v2/…/sha256_… となっている保存されたステージング済みの metadata.json です。
staged_metadata.json ファイルと照合され、3 GB の時点で観測された直接の storage.googleapis.com への multipart PUT リクエストによって裏付けられています(ライブで観測されましたが、そのログは保持されていません。詳細は§7 を参照)。これは AWS S3 ではありません。バイナリは aws-sdk-s3 を使用して代替経路を指し、AWS STS/SSO で認証を行いますが、バイナリ内で指定され、3 GB の時点でネットワーク上で確認された宛先は GCS です。
第三者のテレメトリ:POST api.mixpanel.com/track および /engage(Mixpanel)、および POST grok.com/_data/v1/events がすべて 200 ステータスで送信されます。
設定ドキュメントには明記されていない(スコープ限定の主張):
私は、repo_state や session_state が grok-code-session-traces へアップロードされる様子や、以下の事象を確認できませんでした。
~/.grok/upload_queue は、CLI のインストールスクリプトまたはクイックスタートガイドで説明されているステージング領域です。
確認した資料はこれらです(xAI の全ドキュメントを網羅した完全な監査ではありません。詳細は§7 を参照)。この仕組みは、標準的な一般ユーザーのログインではデフォルトで有効になっています。
信頼性に関する注意(プライバシーとは別問題):~/.grok/upload_queue は1ターンあたり約3GBのスナップショットを一時保存しますが、負荷がかかると数十GBに膨れ上がり、ディスク容量を枯渇させる可能性があります。これはアップロードが成功するかどうかに関わらず存在する実際のバグです。
6. コンセントとポリシー — 正直に明記
- 「クラウド AI ツールはコンテキストを送信します。これは正常な行為です。」 これは事実であり、認められています。コードを処理して実行するためには、あらゆるクラウドベースのコーディングエージェントがサーバーへコードを送信する必要があります。
ここで注目すべき新規性は以下の 3 点です。
(a) シークレットファイル(例:.env)が非加工のまま送信されること。
(b) コンテンツが一時的な処理で終わらず、特定の GCS バケットに永続保存されること。
(c) このアップロード機能が CLI の設定資料(§7 参照)に明記されておらず、デフォルトで有効になっていることです。
- 「利用規約に明記されている/オプトイン制である」 xAI の消費者向けポリシーでは、モデル改善のためのデータ使用について広く開示しており、ユーザーはオプトアウト(grok.com → 設定 → データ → 「モデルを改善する」)が可能です。ただし、プライベートチャットは自動的にオプトアウト状態となり、このオプトアウトは未来のデータにのみ適用され、過去に遡って適用されるものではありません。しかし、広範なトレーニングの開示とは、今回の特定のメカニズムの詳細な文書化を意味しません。 私が確認した CLI の資料には、
repo_state/upload_queue/grok-code-session-tracesというパイプラインに関する記述は見当たりませんでした(§7 で、これは包括的なドキュメント監査ではないと注記されています)。したがって、これらの資料に基づけば、ユーザーは *この特定の仕組み* について知らされていないことになります。
出典:xAI プライバシーポリシー(https://x.ai/legal/privacy-policy)、消費者向け利用規約(https://x.ai/legal/terms-of-service)。
「モデルの改善」トグルは、ON でも OFF でも何の違いもありません。デフォルト設定では、Grok は未読のリポジトリから 5.10 GiB をアップロードしました(§4)。その後、「モデルの改善」をオフにして再実行しましたが、Grok は依然として git bundle 形式でリポジトリ全体をアップロードし続けました(§4(d)、POST /v1/storage → 200、git clone で復元された未読ファイルも含まれます)。 (原文の技術表記: /v1/settings)
「still」の応答では、"trace_upload_enabled": true、"upload_enabled": true、"session_registry_enabled": true が返されており(ファイルごとの上限は 1 GiB の "max_upload_file_bytes": 1073741824)でした。
オプトアウトは学習(トレーニング)に関する規定であり、コードがアップロードまたは保存されるかどうかを決定するものではありません。どちらの場合でも、コードベースのアップロードは grok-code-session-traces に継続されます。
オプトアウトしても、リポジトリが機械から消えるわけではありません。
7. 私たちが証明しなかったこと(知的誠実さについて)
- xAI がこのデータを学習に使用していることを証明したわけではありません。 アップロードや保存と学習は別問題です。これはポリシーやアカウントのティアによって決定されるものであり、私たちが測定したのはデータ転送のみです。
- 直接の
storage.googleapis.com/grok-code-session-tracesへの PUT ワイヤーライン(通信経路)で 3 GB が観測されましたが、このセッションでは保存されていませんでした(スweep 中にログが上書きされ、モデルのクォータ制限により再キャプチャが現在ブロックされているため)。したがって、§4 で主張している「数ギガバイト」という根拠は、保存されたwire_12gb.log(/v1/storageエンドポイントで 75 MB チャンクごとに 200 回成功した記録)と、バケット名を示すバイナリ文字列に基づいています。クォータがリセットされ次第、直接 PUT のキャプチャは再現可能です。
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)
保持されたのは 12 GB のスイープログのみです。64 MB、600 MB、3 GB の各行はライブで観測されましたが、キャプチャログは保存されていません(クォータのリセット後に再現可能です)。また、12 GB のキャプチャ自体はストリーミング中(約 5.1 GB / 73 チャンク捕捉)に停止されたため、「数 GB のアップロードが失敗なく成功する」ことは証明されますが、「12 GB のリポジトリ全体がエンドツーエンドで完了する」という事実を裏付けるものではありません。
「文書化されていない」という主張は範囲限定されたものです。これは xAI のドキュメント、ヘルプセンター記事、ポリシーを網羅的に検索した結果ではなく、CLI のインストールスクリプトとクイックスタートガイドに基づいています。メカニズムが私が確認しなかった箇所に記述されている可能性も否定できません。より正確に言えば、「CLI 自体のセットアップ資料には表示されていない」とするのが妥当な表現です。
チャンネル B(リポジトリ全体)— 現在クローズド(かつて唯一の開放された隙間でした)。証拠§4(d):SuperGrok アカウント上で、単一のラン実行時に POST /v1/storage → 200 を経由して、Grok がGit バンドル形式でリポジトリ全体をアップロードしている様子をワイヤーキャプチャが捉えています。
保存された uploaded_repo.bundle を git clone することで、エージェントに開くなと指示されていたファイル src/_probe/never_read_canary.txt が復元されます。
— 固有のマーカーをそのまま含め、完全な git ヒストリも保持されます。したがって、一度も読まれないファイルの*中身*(ハッシュ値だけでなく)が実際にそのマシンから送信され、受け入れられたことが実証されます。wire_12gb.log の実行は、同じメカニズムが GB 規模のデータ量にも拡張可能であることを示す証拠です。
「汎用型と条件付き(一部回答済み)」:無料枠でも数 GB のアップロードは成功しました。git-bundle 形式のコンテンツアップロードは、SuperGrok で「モデル改善」オプションをオフにした場合にのみ成功します(/v1/settings で trace_upload_enabled: true が返されました)。これらのテストではアップロードを無効にする設定は見つかりませんでしたが、すべてのアカウントや構成の組み合わせを網羅的に検証したわけではないため、「絶対に不可能」とは断言できません。
以前発表された主張の一部は撤回されました:当初の結論「数 GB のデータブロックはローカルで失敗し削除されるだけで、外部へ転送されない」というのは、PID スコープ限定の nettop 測定結果に基づいたものでした。
8. 証拠付録
すべてのアーティファクトと SHA-256 ハッシュ値(MANIFEST.sha256)。バイナリの SHA-256 は 2a97ba675bd992aa9b981e2e83776460d94f469b510c0b8efe28b50d236d767c です。
| アーティファクト | それが証明するもの |
|---|---|
secrets_responses_body.bin (48 KB) | POST /v1/responses ボディ内に .env 内容がそのまま含まれている |
secret_verbatim.txt | 抽出された 2 つの .env 行 |
secrets_session_state.tar.gz (16 KB) | /v1/storage を介してアップロードされたアーカイブ内の同じ機密情報 |
wire_12gb.log | 12 GB リポジトリで 83 回の /v1/storage* → 200 = 82 件のコンテンツ POST (73 チャンク、約 75.0 MB で計 5.10 GiB + 9 件の小ファイル) + 1 件の batch_exists; Channel-A の /v1/responses は合計 196,705 バイト (192 KB) (約 27,800 倍少ない); ストレージ障害なし; 途中まで切り捨て |
model_limit.txt | /v1/responses の失敗 (402×1, 429×3 — モデルクォータ) |
crate_strings.txt | xai-data-collector のパス + grok-code-session-traces + storage.googleapis.com |
binary.sha256 | バイナリの出自 |
gcs_puts.txt | プレースホルダー (空のキャプチャ) — 3 GB の直接 GCS PUT 行は保持されていません; 内部の注釈に理由が記載されており、クォータ (§7) の再キャプチャを待機中 |
uploaded_repo.bundle (152 KB, SHA-256 73b9c0af…) | 決定的な証拠 — POST /v1/storage → 200 を経由して送信された git バンドのワイヤーキャプチャ; git clone で src/_probe/never_read_canary.txt (未読) がそのまま復元され、完全な git ヒストリーも取得可能 (実際の cereblab_api リポジトリ、SuperGrok、「モデルを改善」OFF) |
uploaded_repo_auth.bundle (SHA-256 0ee53653…) | 再現 — 別の無関係なリポジトリ (cereblab_auth Worker) で実施; POST /v1/storage → 200 を経由した git バンド; git clone で未読のキャナリー CANARY-AUTH-4T8K2-NEVERREAD がそのまま復元 |
staged_base_tree_manifest.json | 実コード実行: コードベースのスナップショットマニフェストで src/_probe/never_read_canary.txt (未読) を列挙 + 30 件の実際の src/*.ts ファイル |
staged_metadata.json | 実コード実行: 各ファイルの宛先 fileId: gs://grok-code-session-traces/repo_changes_dedup/v2/…/sha256_… (GCS バケット名を特定) |
再現手順(簡略版):
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
検証結果: すべての通信キャプチャは、私が自身のマシン上で生成したトラフィックのみを対象としています。「機密情報」として扱われたのは偽のキナリ文字であり、実際の認証情報は一切漏洩していません。本調査結果は grok 0.2.93(2026 年 7 月版)に固有のものです。xAI は今後、動作仕様を変更する可能性があります。
AI算出
技術分析ainew評価高い
xAI Grok Build CLI の機密情報漏洩という重大なセキュリティ事実を、キャプチャされたネットワークトラフィックや再現手順に基づいて詳細に分析しており、AI ツールの運用リスクに関する実証的な知見を提供している。ただし、対象は xAI のグローバル製品であり日本固有の規制や企業事例に言及していないため、日本の関連性は限定的となる。
6つの評価軸を見る
- AI関連度
- 100
- 情報源の信頼性
- 50
- 新規性
- 75
- 調べる価値
- 75
- 重複の少なさ
- 100
- 日本での有用性
- 25
関連記事
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み