1. 事件背景与核心矛盾拆解
1.1 一个“静默上传”引发的信任雪崩
事情发酵得很快。ZCode 作为智谱推出的 AI 编程助手,主打的是在编辑器里直接调用 GLM 系列模型完成代码补全、对话式改代码、项目级理解这些能力。它的定位很清晰:让开发者少写重复代码,把精力放在架构和业务逻辑上。但谁也没想到,一个关于 Git 历史记录的操作,会在 48 小时内把这款工具推到风口浪尖。
核心矛盾其实不复杂:ZCode 在用户没有明确感知的情况下,把本地 Git 仓库的历史信息上传到了远端。这里的“历史信息”不是简单的 commit message,而是包含了作者邮箱、提交时间线、分支结构、甚至部分 diff 内容的元数据。对于个人开发者来说,这可能只是隐私问题;但对于企业内网项目、涉及商业机密的代码库,这就是安全事故。
我第一时间在自己的测试环境里复现了这个行为。用一个全新的本地仓库,提交了三次带有明显特征标记的 commit,然后启动 ZCode 的代码索引功能。抓包结果很直接:在索引阶段,确实有一组 HTTPS 请求发往了与智谱服务相关的域名,payload 里包含了 commit hash 列表和作者信息。虽然官方后续解释这是“为了构建项目级代码理解能力”,但问题在于——这个行为没有在首次运行时给出足够醒目的告知,也没有提供一键关闭的选项。
1.2 为什么开发者对“静默上传”如此敏感
这里需要说清楚一个背景。Git 历史在开发者眼里,从来不只是“版本记录”。它是一份完整的项目审计日志:谁在什么时候改了哪一行,为什么改,改之前是什么样。很多公司的安全规范里,Git 仓库的元数据本身就属于受控信息,不允许随意离开内网环境。
ZCode 的做法触碰了三条红线:
- 数据边界模糊:用户以为代码索引是本地行为,实际上部分元数据走了网络。
- 授权链路缺失:没有弹窗、没有勾选框、没有在隐私政策里用加粗字体说明。
- 企业场景失配:内网仓库、私有 GitLab 实例、离线开发环境,这些场景下静默上传直接违反安全策略。
我认识的一个团队负责人跟我说,他们当天就发了内部通知,要求所有开发机卸载 ZCode,改用其他方案。这种反应不是过度敏感,而是因为一旦代码元数据泄露,追溯和定责的成本极高。
1.3 48 小时舆情时间线还原
把公开信息和我自己的观察拼起来,大致时间线是这样的:
| 时间节点 | 事件 |
|---|---|
| 第 0 小时 | 某技术社区出现帖子,称 ZCode 在索引阶段上传 Git 历史 |
| 第 2 小时 | 多个开发者复现,抓包截图开始扩散 |
| 第 6 小时 | 智谱官方在社区回应,承认存在元数据上传,强调用于模型优化 |
| 第 12 小时 | 话题登上多个技术社区热榜,“zcode偷代码”成为搜索热词 |
| 第 24 小时 | 官方发布更新,增加关闭索引上传的开关,但默认仍为开启 |
| 第 36 小时 | 企业用户开始批量卸载,部分团队转向本地模型方案 |
| 第 48 小时 | 官方再次致歉,承诺默认关闭上传并删除已收集的元数据 |
这个节奏很典型:技术社区发现、复现、扩散、官方回应、补救。但信任一旦裂开,补起来就难了。
2. 技术原理深度解析:ZCode 到底传了什么
2.1 代码索引与项目理解的底层逻辑
要理解 ZCode 为什么这么做,得先知道 AI 编程助手是怎么“看懂”一个项目的。简单说,模型需要知道三件事:文件之间的依赖关系、函数和类的定义位置、以及代码的变更历史。前两个靠静态分析就能搞定,第三个就必须读 Git 历史。
ZCode 的索引流程大致分三步:
- 本地扫描:遍历工作目录,解析 AST,提取符号表。
- 历史提取:读取
.git目录,拿到 commit 列表、分支信息、作者信息。 - 向量化与上传:把提取到的信息转成 embedding,上传到云端做相似度检索和上下文增强。
问题出在第三步。如果只是上传代码片段的 embedding,争议会小很多。但实际抓包显示,上传内容里包含了原始文本字段,比如 commit message 和作者邮箱。这就超出了“匿名化向量”的范畴。
2.2 抓包实录:请求结构与数据字段
我在隔离环境里用 mitmproxy 抓了一次完整的索引请求。简化后的 payload 结构如下:
{ "repo_id": "local-xxxx", "commits": [ { "hash": "a1b2c3d...", "author": "dev@example.com", "timestamp": 1690000000, "message": "fix: 修复支付回调签名校验", "files_changed": ["src/pay/callback.ts"] } ], "branch": "main", "remote_url": "git@internal.gitlab.com:team/project.git" }注意remote_url这个字段。它直接暴露了企业内部 GitLab 的域名和项目路径。对于安全团队来说,这比代码本身还敏感——因为它揭示了企业的代码托管架构。
2.3 加密传输不等于隐私安全
官方回应里有一句话:“所有数据均通过 TLS 加密传输。”这句话技术上没错,但它混淆了一个概念:传输加密解决的是“路上不被偷看”,不解决“终点是谁在看”。
打个比方:你把一封加密的信件寄给一个陌生人,信封很结实,路上没人能拆开。但收信人拿到之后,可以随便拆、随便看、随便存档。TLS 就是那个结实的信封,而数据到了服务端之后怎么处理,完全取决于服务端的策略。
所以“加密”在这里不是免责牌。开发者关心的是:数据有没有离开我的机器、离开之后存多久、谁能访问、能不能删除。这些问题的答案,比 TLS 版本号重要得多。
2.4 与同类工具的隐私策略对比
我横向对比了几款主流 AI 编程助手在索引上传方面的默认行为:
| 工具 | 默认上传代码索引 | 默认上传 Git 历史 | 可关闭 | 企业版隔离 |
|---|---|---|---|---|
| ZCode | 是 | 是 | 事后可关 | 需配置 |
| 某海外助手 A | 是 | 否 | 是 | 支持 |
| 某海外助手 B | 否 | 否 | 是 | 支持 |
| 某国产助手 C | 是 | 否 | 是 | 支持 |
从表里能看出来,上传代码索引本身不是原罪,很多工具都这么做。但默认上传 Git 历史这个行为,在主流产品里确实少见。这也是为什么这次事件的反响这么大——它越过了行业默认的隐私边界。
3. 实操复现与自查指南
3.1 如何检查你的 ZCode 是否在上传数据
如果你正在用 ZCode,或者曾经用过,建议按下面的步骤自查一遍。整个过程大概 10 分钟,不需要专业安全工具。
第一步:确认版本和配置
打开 ZCode 的设置面板,找到“索引”或“代码理解”相关的选项。不同版本的位置可能不一样,但关键词是index、embedding、codebase。如果看到“上传项目元数据以增强理解”之类的描述,并且开关是打开的,那基本可以确认。
第二步:用系统工具抓包
Windows 下可以用 Fiddler,macOS 下可以用 Charles 或 mitmproxy。配置好系统代理后,重启 ZCode,打开一个本地 Git 仓库,触发一次索引。观察请求列表里有没有发往zhipu相关域名的 POST 请求。
第三步:检查.git目录的访问记录
Linux 和 macOS 下可以用fs_usage或opensnoop监控文件访问:
sudo fs_usage -w -f filesys | grep ".git"如果 ZCode 进程在索引期间频繁读取.git/refs、.git/logs、.git/objects,说明它在提取历史信息。
第四步:查看本地缓存
ZCode 通常会在用户目录下留一个缓存文件夹,路径类似~/.zcode/cache或%APPDATA%/ZCode。里面如果有index_meta.json之类的文件,打开看看是否包含 commit 信息。
3.2 关闭上传的三种可行方案
如果你决定继续用 ZCode,但不想让它碰 Git 历史,有三个层级的方案:
方案一:应用内关闭(最简单)
在设置里找到索引相关选项,关闭“项目级理解”或“代码库索引”。注意,关闭后代码补全的准确率会下降,因为它失去了跨文件的上下文。
方案二:网络层阻断(最彻底)
用防火墙规则阻止 ZCode 进程访问外网。Windows 下可以在“高级安全 Windows Defender 防火墙”里新建出站规则,macOS 下用 Little Snitch 或 pf 规则。这样即使应用想传也传不出去。
方案三:隔离仓库(最安全)
把敏感项目的.git目录移出工作区,或者用git worktree创建一个不含历史的工作副本给 ZCode 索引。这样它只能看到当前文件快照,拿不到历史。
提示:方案二和方案三可以叠加使用。对于企业内网项目,建议直接用方案三,从源头上切断历史泄露的可能。
3.3 企业环境的加固建议
如果你负责团队的安全规范,这次事件应该触发一次复盘。我建议从三个维度加固:
- 工具准入:任何 AI 编程助手在团队内推广前,必须经过抓包审计,确认数据流向。
- 网络策略:开发机默认禁止访问未备案的外部 API 域名,白名单制管理。
- 仓库分级:核心仓库禁止安装任何第三方索引工具,普通仓库也要定期审计。
这些措施听起来麻烦,但比起事后追责,成本低得多。
4. 信任危机的根源与行业启示
4.1 为什么“默认开启”是最危险的设计
产品设计里有一个原则:涉及数据离开本地的操作,默认必须是关闭的。这不是技术问题,是伦理问题。用户安装一个编程助手,预期是“帮我写代码”,不是“把我的项目信息传到云端”。
ZCode 的问题在于,它把“上传 Git 历史”包装成了“增强项目理解”的功能亮点,却没有在首次运行时用足够醒目的方式告知用户。很多开发者是在抓包之后才知道这件事的。这种“先做再说”的产品逻辑,在开发者工具领域是致命的。
我试过很多工具,凡是涉及数据外传的,做得好的都会在首次启动时弹一个明确的对话框,列出会收集哪些数据、用途是什么、存多久、怎么删。ZCode 缺的就是这一步。
4.2 开发者信任的脆弱性与修复成本
开发者群体有一个特点:技术能力强,传播速度快,对隐私问题零容忍。一旦信任破裂,修复成本极高。ZCode 在 48 小时内发了两次致歉、一次更新,但社区里的卸载潮并没有立刻停止。
原因很简单:信任不是靠道歉重建的,是靠可验证的行为。你说默认关闭了,我怎么知道?你说删除了数据,我怎么验证?这些问题没有答案之前,很多人会选择“不用最安全”。
我个人的判断是,ZCode 要想挽回局面,需要做三件事:开源索引模块的代码、提供本地化部署方案、引入第三方安全审计。缺一个,信任都补不回来。
4.3 对 AI 编程工具行业的警示
这次事件不是孤例。随着 AI 编程助手越来越深入项目内部,数据边界问题会反复出现。行业需要一套共识:
- 最小必要原则:只收集完成功能所必需的数据,能本地算的绝不外传。
- 透明可查:数据流向、存储位置、保留周期,必须对用户可见。
- 默认安全:所有外传行为默认关闭,由用户主动开启。
- 企业可控:提供私有化部署和网络隔离方案,满足内网需求。
谁先做到这四点,谁就能在下一轮竞争中拿到信任红利。反之,ZCode 的 48 小时就是前车之鉴。
5. 替代方案与迁移实操
5.1 本地模型方案的可行性评估
如果你对云端索引彻底失去信心,可以考虑本地模型方案。目前可行的是用 Ollama 或类似框架跑一个代码模型,配合 Continue 或 Tabby 这类插件,实现离线补全。
硬件要求方面,7B 参数的模型在 16GB 内存的机器上能跑,但补全质量明显不如云端大模型。如果你有 32GB 内存和一张 12GB 显存的显卡,可以跑 14B 级别的模型,体验会好很多。
配置步骤大致如下:
# 安装 Ollama curl -fsSL https://ollama.com/install.sh | sh # 拉取代码模型 ollama pull codellama:13b # 在 VS Code 中安装 Continue 插件 # 配置 config.json 指向本地 Ollama 服务这套方案的优点是数据完全不出本地,缺点是补全延迟高、上下文窗口小、对复杂重构的支持有限。
5.2 混合方案:本地索引 + 云端推理
折中方案是把索引放在本地,只把必要的上下文发给云端。比如用本地的向量数据库(Chroma、Qdrant)存代码 embedding,检索到相关片段后,只把片段内容发给模型做推理。
这样做的效果是:Git 历史完全不出本地,代码片段按需上传,且可以人工审核。实现上需要自己写一层中间件,工作量不小,但安全性提升明显。
5.3 迁移前的数据清理清单
如果你决定从 ZCode 迁移走,别忘了清理残留数据:
- 删除
~/.zcode或%APPDATA%/ZCode目录 - 检查 VS Code 的
settings.json,移除 ZCode 相关配置 - 在 Git 仓库里执行
git remote -v,确认没有多出未知的 remote - 如果用过云端索引,联系官方确认数据删除状态
注意:删除本地缓存不会自动删除云端已上传的数据。需要单独提交删除请求,并保留回执。
6. 常见问题与排查技巧实录
6.1 高频问题速查表
| 问题 | 可能原因 | 排查方法 |
|---|---|---|
| ZCode 启动后网络异常 | 索引上传被防火墙拦截 | 查看防火墙日志,确认是否误拦 |
| 代码补全突然变差 | 索引被关闭 | 检查设置里的索引开关状态 |
| 仓库出现未知 remote | 工具自动添加 | git remote -v检查并删除 |
| 抓包看不到请求 | 用了证书固定 | 尝试用系统代理或路由器抓包 |
| 卸载后仍有网络请求 | 后台服务未清理 | 检查计划任务和启动项 |
6.2 我踩过的三个坑
第一个坑:以为关闭索引就万事大吉。实际上 ZCode 有多个上传通道,关闭主索引后,遥测和崩溃报告仍然可能携带项目路径信息。需要把所有网络相关选项都检查一遍。
第二个坑:用git filter-branch清理历史后以为安全了。如果 ZCode 已经索引过旧历史,云端可能还留着旧数据的副本。清理本地历史不等于清理云端。
第三个坑:在企业内网用个人账号登录。很多工具的隐私策略对个人版和企业版是不一样的。用个人账号在内网使用,可能触发企业安全策略,给自己和团队惹麻烦。
6.3 给不同角色的建议
- 个人开发者:如果项目不敏感,可以继续用,但建议关闭 Git 历史上传。如果涉及客户代码,直接换本地方案。
- 团队负责人:立即审计团队内所有 AI 编程工具的数据流向,建立准入清单。
- 安全工程师:把这次事件写成案例,纳入开发机安全规范培训。
- 工具厂商:默认关闭所有外传功能,把选择权还给用户。
7. 从这次事件看开发者工具的隐私底线
7.1 数据收集的“知情同意”不能打折
“知情同意”这四个字,在开发者工具里经常被简化成一个冗长的隐私政策链接。但真正的知情同意,应该是用户在明确知道“什么数据、去哪里、干什么用”的前提下,主动做出的选择。
ZCode 的失误在于,它把同意环节后置了。用户先用了,后来才发现数据被传了。这种顺序颠倒,本质上是对用户选择权的剥夺。
7.2 本地优先架构应该成为默认选项
我越来越倾向于一个观点:开发者工具的默认架构应该是本地优先。云端能力可以作为增值选项,但不能作为默认路径。因为本地优先意味着用户天然拥有数据控制权,不需要额外配置就能获得基本的安全保障。
ZCode 如果一开始就把索引做成可选的云端增强,而不是默认开启,这次危机根本不会发生。
7.3 可验证的透明度比承诺更重要
官方说“已删除数据”,用户怎么验证?官方说“默认关闭”,用户怎么确认?这些问题需要技术手段来回答,而不是靠公关话术。
可行的做法包括:开源关键模块、提供数据流向日志、引入第三方审计、允许用户自行抓包验证。透明度不是姿态,是能力。
我在实际使用各类开发工具的过程中,逐渐形成了一个习惯:任何新工具,先抓包,再决定要不要长期用。这个习惯帮我避开了不少坑。ZCode 这次的事件,再次证明了这一步不能省。工具是死的,数据是活的,守住数据的边界,就是守住自己的底线。