安全研究者cereblab用抓包工具mitmproxy盯上了Grok Build CLI 0.2.93,结果发现这个号称"本地优先"的编程助手,会把用户整个Git仓库——连带完整提交历史——原样打包,传到一个叫grok-code-session-traces的Google云存储桶里。测试用的12GB仓库里,模型回答任务真正需要的数据只有约192KB,而后台悄悄传走的是5.1GB。研究者预埋在.env文件里的一枚诱饵密钥,在抓包记录里原样明文出现,没有做任何脱敏。

这不是"顺手多传了点日志"的量级差距,是任务需求和实际传输相差了两万多倍。

仓库打包和任务问答,走的根本不是一条路

大多数开发者会默认,AI编程工具传给云端的应该是它"看过"的那部分代码——你打开哪个文件,它读哪个文件。但这次抓包显示,仓库上传和模型请求走的是两个完全独立的通道,一个负责回答你的问题,一个在后台把整个仓库原样搬走。哪怕你明确指示Agent"不要读某个文件",打包上传照样按计划执行。

这说明问题不在某次配置失误,而在于打包上传的逻辑压根没跟Agent实际执行任务的路径挂钩,是两套独立系统。

"训练开关"关了,代码还是走了

Grok Build界面上有一个"Improve the model"开关,大多数用户会理解成"我不同意,我的数据就不会被收走"。研究者实测发现,关掉这个开关之后,服务端返回的仍然是trace_upload_enabled: true,仓库上传照常进行。真正管控数据是否离开设备的,是一个从未出现在任何设置界面、也没写进任何文档的服务端标志位。

  • 风险.用户以为自己关掉了数据收集,实际关掉的只是"是否同意训练",仓库照样在传,这个落差在产品界面上完全看不出来。

这是一种典型的"开关剧场"——界面给你一个可以点的按钮,让你产生"我已经做了隐私选择"的错觉,但真正决定数据出站与否的逻辑藏在你够不到的地方。行业里给企业客户的Zero Data Retention协议,通常明确写着推理层不持久化保存代码和提示词,但xAI的官方文档从没说清楚,仓库级别的整体打包上传是否也算在这个承诺范围里,消费级用户就更没有对应说法。

曝光第二天,服务端悄悄改了标志位

报道公开次日,同一台0.2.93客户端被重新测试,服务端这次返回的是disable_codebase_upload: truetrace_upload_enabled: false,连续六次重测,都没有再观察到仓库上传。这更像是一次远程静默下发的修复,没有安全公告,没有说明,官方在同一时间发布的0.2.98更新日志里,一个字都没提这件事。

问题是这次验证只覆盖了一台机器、一个账号。修复是不是全局生效,此前收进grok-code-session-traces桶里的仓库会不会删除,xAI有没有用这些代码训练过模型——目前全部没有答案。研究者本人也说得很克制:抓包证据只能证明"未披露的收集"发生过,证明不了"训练"或"员工查看"这类更严重的指控。

修复了传输行为,没修复的是信任缺口。

同类工具都在传代码,披露程度天差地别

Agentic coding工具要理解整个仓库,就必然要把代码内容送到云端做上下文处理,这是行业的共同结构,不只是xAI一家的问题。区别在于披露的清晰度。

工具数据出站机制留存说明
CursorPrivacy Mode下代码分块生成嵌入向量明文代码用完即删,但嵌入向量、文件哈希可能保留
Claude Code消费级用户数据可用于模型改进最长留存5年,选择退出训练则30天内清除
Gemini CLI默认开启使用统计,遥测默认关闭是否记录提示词内容取决于用户手动配置
Grok Build仓库整体打包上传,训练开关关闭仍在传无公开文档,事发前设置页面未提及此机制

前三家至少在文档里给出了一个可查的留存期限或退出路径,Grok Build在曝光之前,这套机制根本没在任何用户可见的地方出现过。这不是同一起隐私问题的不同版本,是透明度台阶上明显更低的一级。

对已经在私有代码库上跑过这个CLI的团队来说,眼下能做的现实动作是:立刻轮换所有可能被明文传输过的密钥,审计.env等敏感文件是否被这套工具接触过,再决定要不要继续把它放进研发工具链的白名单。指望厂商的隐私开关,不如指望网络层的实际抓包结果——这次事件已经证明,前者靠不住。