grok 0.2.93의 네트워크 트래픽을 직접 캡처한 결과, Grok Build는 읽은 파일을 마스킹 없이 전송하고session_state로 저장했으며 테스트용.env비밀값도 두 경로에 그대로 포함했음- 모델 요청이 에이전트가 읽은 파일을 보내는 것과 별개로, 모든 추적 파일과 Git 이력을 담은 저장소 전체가 git bundle로 업로드됐고 열지 말라고 지정한 파일도 원문 그대로 복구됐음
- 12GB 무작위 파일 저장소에서
/v1/responses요청은 총 192KB였지만/v1/storage전송량은 캡처 중단 시점까지 5.10GiB에 달해 약 27,800배 차이가 났으며, 모든 저장 요청이 HTTP 200을 반환했음 - 업로드 목적지는 Google Cloud Storage의
grok-code-session-traces버킷이었고, “Improve the model”을 꺼도trace_upload_enabled: true와upload_enabled: true가 유지되며 전체 저장소 업로드가 계속됐음 - 실험은 데이터의 전송·수락·저장을 입증하지만 모델 학습에 사용됐는지는 확인하지 못했으며,
.gitignore파일과 모든 계정·설정 조합도 시험하지 않아 결과는 2026년 7월의 특정 버전에 한정됨
테스트 대상과 분석 범위
- 대상은 일반 소비자 계정으로 로그인한 xAI 공식 Grok Build CLI였음
- 설치 경로는
~/.grok/bin/grok - 브라우저에서 X 또는 SuperGrok 계정으로 인증하며 API 키는 사용하지 않음
- 테스트 바이너리는 Apple Silicon용
grok 0.2.93 (f00f96316d4b)임 - SHA-256은
2a97ba675bd992aa9b981e2e83776460d94f469b510c0b8efe28b50d236d767c임 - 바이너리 문자열에서 자체 Rust 업로드 구성요소와 저장소 관련 상수가 확인됐음
crates/codegen/xai-data-collector/src/gcs.rsstorage_client.rs,queue.rs,file_access_tracker.rs,circuit_breaker_observer.rsxai-grok-shell/src/upload/{gcs,turn,trace,manifest}.rsgrok-code-session-traces,storage.googleapis.com,Uploading bytes to GCS via proxy- 모든 캡처는 테스트 수행자의 컴퓨터와 트래픽만을 대상으로 했으며, 저장소에는 실제 자격 증명 대신 고유 canary 문자열을 넣었음
재현 및 트래픽 캡처 방법
- macOS Apple Silicon에서
mitmproxy의 CA를 로그인 키체인에 신뢰 인증서로 추가하고HTTPS_PROXY와SSL_CERT_FILE을 설정해 Grok의 HTTPS 요청을 캡처함 - Grok은 이 구성에서 인증서 고정(certificate pinning) 으로 캡처를 차단하지 않았음
mitmdump애드온으로 요청별 메서드, 호스트, 경로, 응답 상태, 요청 바이트 크기를 기록하고 xAI 호스트로 향하는 요청 본문을 저장함~/.grok/upload_queue/*를 실행 중 복사한 뒤gzip과tar로 풀어 전송 대기 중인 스테이징 아티팩트도 검사함- 각 파일에는 출처를 구분할 수 있는 고유 마커를 넣었으며, 비밀 파일에는 다음과 같은 가짜 값을 사용함
API_KEY=CANARY7F3A9-SECRET-should-not-leaveDB_PASSWORD=CANARY7F3A9-DBPASS
채널 A: 읽은 파일과 .env의 모델 요청 전송
- Grok이 읽은 파일 내용은
POST cli-chat-proxy.grok.com/v1/responses의 모델 턴 본문에 직렬화됐음 - 캡처된 48,070바이트 요청에는
"model":"grok-4.5"와 메시지 배열이 포함됐음 .env의API_KEY와DB_PASSWORDcanary가 줄바꿈까지 원문 그대로 발견됐음- 소스, 로직, README, 중첩된 JavaScript 파일과 두 비밀값을 포함한 6개 마커를 요청 본문에서 복구할 수 있었음
- 같은 내용은
session_state아카이브에도 들어가POST /v1/storage로 업로드됐으며, 해당 저장 요청은 HTTP 200으로 수락됐음 - 압축 아카이브를 풀어 검사하자 두 비밀값과 다른 파일 마커가 모두 발견됐음
- 비밀값은 모델이 일시적으로 처리하는 데 그치지 않고 저장용 아카이브에도 기록됐음
Reply exactly OK, do not read any files라는 통제 프롬프트에서는 열지 않은untouched_secret.txt의 마커가/v1/responses본문에 나타나지 않았음- 이는 모델 요청 채널이 에이전트가 실제로 읽은 파일을 중심으로 구성된다는 범위만 입증함
- 별도의 저장소 전체 스냅샷 채널에는 읽지 않은 파일도 포함되므로, 이 통제 결과가 전체 저장소 업로드를 부정하지는 않음
- 비밀값은
.env또는secrets.env에 있었고 Git으로 추적되는 파일이었음 .gitignore에 포함된 파일도 업로드되는지는 별도로 시험하지 않았음- canary는 실제 고엔트로피 토큰 형식이 아니므로
sk-…같은 특정 형태를 위한 별도 마스킹 장치가 전혀 없다고까지 입증하지는 않음 - 확인된 범위는 테스트한
.env내용이 마스킹되지 않은 채 전송됐다는 점임
채널 B: 읽지 않은 파일까지 포함한 저장소 전체 업로드
/v1/storage는 모델이 읽은 파일을 보내는/v1/responses와 별개로 작업 공간 전체 스냅샷을 업로드했음- 실제
cereblab_api저장소에서Reply with exactly: OK. Do not read or open any files.라고 지시한 뒤 실행함 - Grok은
POST /v1/storage로 152,102바이트 git bundle을 전송했고 서버는 HTTP 200을 반환했음 - 캡처한
uploaded_repo.bundle을git clone하자 열지 말라고 지정한src/_probe/never_read_canary.txt가 복구됐음 - 파일 안의
CANARY-XR47P2-NEVERREAD-UNIQUE마커도 원문 그대로 남아 있었음 - bundle에는 4개 커밋, 47개 파일과 전체 Git 이력이 포함됐음
- 두 번째 독립 저장소
cereblab_auth에서도 같은 결과가 재현됐음 POST /v1/storage로 31,743바이트 git bundle이 업로드되고 HTTP 200을 반환했음- 복원된 저장소에서 읽지 않은 파일의
CANARY-AUTH-4T8K2-NEVERREAD마커가 그대로 확인됐음 - 별도의 298개 파일 규모
cereblab_api실행에서는 스테이징된 manifest가 읽지 않은 파일까지 열거했음 src/_probe/never_read_canary.txt와src/apns.ts,src/index.ts등의 실제 소스가 함께 기록됐음metadata.json의 파일별fileId는gs://grok-code-session-traces/repo_changes_dedup/v2/supplemental/sha256_…형태였음- 이 실행은 할당량에 막혀 콘텐츠 blob 전송까지 완료하지 못했지만, 별도의 git bundle 실험과 12GB 실험에서 실제 업로드가 확인됐음
- 바이너리에는
after_codebase.tar.gz,repo_state.upload,collecting workspace files,spawning background coordinator같은 문자열도 포함돼 작업 공간 수집 메커니즘과 일치했음
12GB 저장소에서 확인한 다중 GiB 전송
- 압축이 거의 되지 않는 무작위 파일로 저장소 크기를 늘리며 업로드 동작을 관찰함
- 64MB에서는 약 48MB 크기의 단일
POST /v1/storage가 HTTP 200을 반환했지만 로그는 보존하지 못함 - 약 600MB에서는 약 7.5MB 청크 수십 개가 모두 HTTP 200을 반환했으나 로그가 남아 있지 않음
- 약 3GB에서는 multipart 초기화 후
storage.googleapis.com으로 50MB 단위 PUT이 관찰됐지만 직접 PUT 로그는 보존하지 못함 - 약 12GB에서는 약 75MB 청크를
/v1/storage로 계속 전송했으며 5.10GiB 시점에서 캡처를 중단함 - 보존된
wire_12gb.log에는/v1/storage*HTTP 200 응답이 총 83개 있음 - 콘텐츠 업로드
POST /v1/storage82개 - 이 가운데 약 75MB 청크 73개
- 73개 청크의 합계는
5,476,083,317B, 즉 5.10GiB 또는 5.48GB임 - 작은 POST 9개와
/v1/storage/batch_exists중복 확인 1개도 포함됨 - 전체
/v1/storage*요청 바이트는5,476,228,005B이며 실패한 저장 요청은 없었음 - 캡처는 업로드가 계속되는 중에 중단됐으므로 12GB 전체 업로드 완료를 입증하지는 않음
- 마지막 기록도 약 75MB 청크에 대한 HTTP 200이었음
- 입증된 범위는 5.10GiB 이상이 실패 없이 전송됐고 중단 시점에도 계속 증가하고 있었다는 것임
- 같은 세션의 두 채널 사이에는 큰 용량 차이가 있었음
/v1/responses는 5개 요청을 합쳐196,705B, 약 192KB였고 가장 큰 요청도 60,394B였음/v1/storage는 5.10GiB였음- 약 27,800배 차이가 발생해 모델 요청에 포함되지 않은 대량의 저장소 데이터가 별도 저장 채널로 이동했음
- 모델 할당량 오류와 저장 업로드는 독립적으로 발생했음
/v1/responses에서 HTTP 402가 1회, 429가 3회 발생함- 세션 bookkeeping 요청에서는 관련 없는 404가 1회 발생함
- 첫 429 이후에도
/v1/storageHTTP 200이 76회 이어졌음 - 저장 요청 82개는 모두 성공했으며 테스트 범위에서 저장 용량 제한 오류는 발생하지 않았음
- 이 결과는 로컬
upload_queue가 비워지는 현상에 의존하지 않음 - 큐는 업로드 성공과 폐기 모두에서 비워질 수 있어 증거로 사용하지 않았음
- 근거는 요청 본문이 실제 네트워크로 나가 HTTP 200을 받은 캡처와 업로드된 git bundle에서 파일을 복구한 결과임
저장 위치와 원격 측정
- 저장 목적지는 AWS S3가 아니라 Google Cloud Storage의
grok-code-session-traces버킷으로 확인됐음 - 바이너리에
grok-code-session-traces,storage.googleapis.com,Uploading bytes to GCS via proxy가 포함됐음 - 보존된
metadata.json의 파일 목적지가gs://grok-code-session-traces/…로 기록됐음 - 약 3GB 실험에서는 해당 GCS 호스트로 직접 multipart PUT도 관찰했지만 로그는 보존하지 못함
- 바이너리에
aws-sdk-s3가 포함돼 있어도 테스트에서 확인된 목적지는 GCS였음 - 제3자 및 자체 원격 측정 요청도 확인됐음
- Mixpanel의
api.mixpanel.com/track과/engage grok.com/_data/v1/events- 해당 요청은 모두 HTTP 200을 반환했음
- 검토한 CLI 설치 스크립트와 quickstart 자료에서는
repo_state,session_state,~/.grok/upload_queue,grok-code-session-traces업로드를 찾지 못했음 - 모든 xAI 문서와 도움말을 조사한 것은 아니므로 어디에도 문서화되지 않았다고 단정할 수 없음
- 확인 가능한 범위는 CLI 자체 설정 자료에서 드러나지 않았다는 것임
~/.grok/upload_queue는 한 턴에 약 3GB 스냅샷을 스테이징할 수 있고 부하가 높으면 수십GB까지 증가해 디스크를 소진할 수 있었음- 이는 업로드의 개인정보 문제와 별개인 신뢰성 문제임
“Improve the model” 설정과 정책 범위
- 클라우드 코딩 에이전트가 작업에 필요한 코드 문맥을 서버로 보내는 행위 자체는 필요한 동작임
- 테스트에서 확인된 동작은 다음 세 가지로 구분됨
.env같은 비밀 파일을 마스킹 없이 전송함- 해당 내용을 명시된 GCS 버킷에 저장함
- 저장소 전체 업로드가 검토한 CLI 설정 자료에 드러나지 않은 채 기본 활성화돼 있음
- xAI 소비자 정책은 모델 개선을 위한 데이터 이용과 opt-out을 광범위하게 다루며, Private Chat은 자동 opt-out이고 opt-out은 소급 적용되지 않음
- 관련 문서는 xAI Privacy Policy와 Consumer ToS임
- 이러한 일반적 학습 정책은 특정
repo_state및 GCS 업로드 파이프라인을 문서화하는 것과 같지 않음 -
“Improve the model”을 꺼도 업로드는 중단되지 않음
-
설정을 끈 상태에서도 전체 저장소가 git bundle로
/v1/storage에 업로드됐고 HTTP 200을 반환함 git clone으로 읽지 않은 파일과 Git 이력을 복구할 수 있었음- CLI가 받은
/v1/settings에는"trace_upload_enabled": true,"upload_enabled": true,"session_registry_enabled": true가 유지됐음 "max_upload_file_bytes": 1073741824로 파일당 1GiB 제한도 반환됐음- 테스트 결과에서 opt-out은 학습 여부를 제어하지만 저장소가 컴퓨터를 떠나 업로드·저장되는 동작은 차단하지 않았음
입증하지 않은 사항과 증거의 한계
- 네트워크 캡처만으로는 xAI가 데이터를 모델 학습에 사용한다는 사실을 입증할 수 없음
- 확인된 범위는 전송, HTTP 200 수락, 저장용 아카이브와 GCS 목적지임
- 3GB 실행에서 관찰한
storage.googleapis.com/grok-code-session-traces직접 PUT 로그는 덮어써져 보존되지 않았음 - 다중 GiB 업로드 근거는 보존된 12GB 실행의
/v1/storage로그와 버킷을 명시한 바이너리 및 metadata임 - 크기별 시험 중 64MB, 600MB, 3GB 로그는 남아 있지 않고 12GB 로그만 보존됐음
- 12GB 실행은 약 5.10GiB에서 중단됐으므로 전체 12GB가 끝까지 업로드된다고 단정할 수 없음
- 모든 계정 등급과 구성 조합을 시험하지 않았음
- 무료 등급에서 다중 GiB 업로드가 성공했음
- SuperGrok에서는 “Improve the model”을 끈 상태에서도 git bundle 업로드가 성공했음
- 테스트에서 업로드를 끄는 설정을 찾지 못했지만 어떤 환경에서도 절대 비활성화할 수 없다고 단정하지 않음
- 초기에는 PID 단위
nettop결과를 근거로 대용량 blob이 업로드되지 않았다고 잘못 판단했으나 이를 철회함 - 별도 업로드 조정 프로세스와 Google IP로 직접 향하는 사전 서명 PUT은 API 호스트나 단일 PID 기준 측정에서 빠질 수 있었음
- 이후의 프록시 와이어 캡처가 초기 판단을 대체함
- 결과는
grok 0.2.93, macOS Apple Silicon, 2026년 7월 환경에 한정되며 xAI가 이후 동작을 변경할 수 있음
보존된 주요 증거
secrets_responses_body.bin:.env원문이/v1/responses본문에 포함됐음을 보여줌secrets_session_state.tar.gz: 같은 비밀값이/v1/storage용 아카이브에 들어 있음을 보여줌wire_12gb.log: 5.10GiB 저장 업로드, 83개/v1/storage*HTTP 200, 저장 실패 0건과 두 채널의 약 27,800배 용량 차이를 기록함model_limit.txt: 모델 요청에서 발생한 402 1회와 429 3회를 기록함crate_strings.txt:xai-data-collector,grok-code-session-traces,storage.googleapis.com문자열을 보존함uploaded_repo.bundle: 업로드된 git bundle에서 읽지 않은 파일과 전체 Git 이력을 복구한 첫 번째 저장소 증거임uploaded_repo_auth.bundle: 두 번째 독립 저장소에서 같은 결과를 재현한 증거임staged_base_tree_manifest.json: 읽지 않은 파일이 저장소 스냅샷 manifest에 열거됐음을 보여줌staged_metadata.json: 파일 목적지가gs://grok-code-session-traces/…임을 보여줌gcs_puts.txt는 직접 GCS PUT을 보존하지 못해 비어 있는 placeholder이며, 해당 PUT의 보존 증거로 사용할 수 없음