一、这件事为什么值得每个开发者读完
9 月 18 日,开发者 ferstar 清磁盘时发现 ~/.zcode 占了 700MB 以上,顺手翻了一下,翻出一个 313MB 的 .enc 加密包。顺着这个包,整条链路被拉了出来:智谱 AI 编程工具 ZCode 在登录状态下,会把用户本地 Git 仓库整个打包加密后上传到阿里云 OSS。
随后是一套标准的危机公关节奏:9 月 18 日官方在用户群致歉,9 月 19 日推 v3.14.0 移除相关入口,9 月 20 日宣布 MaaS 平台"数据内容不留存",9 月 21 日以 Apache-2.0 开源 ZCode 桌面端、浏览器端、后端服务与终端 Agent。中国信通院与绿盟科技亦入场做第三方审计。
到 9 月 22 日,事实层面的新进展已经落地(开源 + 审计结论),而争议层面反而更热了——因为审计结论只证明了"数据已删除",证明不了"数据没被用过"。这条边界,正是本文想讲清楚的东西。

二、技术拆解:它到底做了什么
2.1 最硬的证据是一个"失败"的包
整起事故最可信的部分不是任何一方的话,而是本地物证。据 FreeBuf 报道,~/.zcode/v2/checkpoints/ 下那个 313MB 加密包对应约 345MB 工作区内容,而它的状态文件里写着 failureCount: 564——因为网络问题连续 564 次上传失败,这个包才滞留本地,才被人看见。
这句话反过来读更冷:如果这 564 次里成功过一次,这个行为大概永远不会被发现。
2.2 链路:客户端拿公钥,密文直传 OSS,私钥只在云端
逆向 app.asar 后得到的路径清晰可复盘(据 Yahoo Tech 报道):
关键点在最后:RSA 私钥只存在云端。也就是说,用户连本地这份密文自己都解不开。你想自查"到底上传了什么",只能看到文件名和体积——这本身就是一种刻意的不可审计设计。
2.3 打包范围严重偏向版本历史
如果只是"把当前代码发给模型读",争议会小很多。但一份 42,411 个文件的快照清单统计显示(据 runtimewire 报道):
| .git/lfs/ 缓存 | 196.1 MB | 56.8% |
| .git/objects | 102.2 MB | 29.6% |
| reflog | 0.6 MB | 0.2% |
| .git 合计 | — | 86.6% |
| 源码与文档 | 约 46.2 MB | 13.4% |
.git 占 86.6%,源码文档只占 13.4%。这意味着被搬走的不是"你现在写的代码",而是你的完整提交历史、LFS 大文件、未推送分支名、内网主机名,以及那些早就从工作区删掉、但还留在历史里的密钥配置。
2.4 触发时机:不是定时任务,是"每次提问前"
据 FreeBuf 报道,sidecar 进程随登录常驻,触发点是 captureBeforePrompt(每次提问前)以及任务完成 / Repo Wiki 更新时,属无条件触发;单个活跃会话中最多出现 62 次捕获。手动删掉待传的加密包后,约半小时内会自动重新打包并继续重试。
结论很直接:“我只用它问了几个问题"和"我把整个私有仓库交给它”,在数据后果上没有区别。

三、两个隐私开关,一个都没拦住
UI 上其实有两个看起来相关的开关:「优化体验」和「仓库快照索引」。但实际上:
- 「优化体验」只控制数据是否用于模型训练;
- 「仓库快照索引」只控制服务端是否建立索引。
两者都与"要不要打包上传"完全解耦。隐私政策文本中也未提及整库快照和 Git 历史的上传(据 habr 报道)。这和 xAI Grok Build 的 improve_model_enabled / trace_upload_enabled 属于同一类设计——开关给的是心理安慰,不是技术边界。
四、动手自查:给编码 Agent 立三道技术边界
以下动作与具体厂商无关,任何拿到你代码和凭据的桌面 Agent 都值得这样过一遍。
4.1 检查本地残留物
# 看有没有体积异常的本地缓存
du -sh ~/.zcode ~/.cursor ~/.codeium 2>/dev/null
# 找大体积加密包与状态文件
find ~/.zcode -name '*.enc' -size +10M -exec ls -lh {} \\; 2>/dev/null
find ~/.zcode -name '*.json' -exec grep -l 'failureCount\\|retry' {} \\; 2>/dev/null
任何"本地缓存目录里出现几十上百 MB 的加密包",都值得问一句:这个包本来是打算发给谁的。
4.2 用 mitmproxy 观察真实外发体积
不要相信 UI 上的开关文案,抓包只认字节数。下面这个附加脚本会打印每个域名的累计外发量:
# watch_upload.py —— 用法: mitmproxy -s watch_upload.py
from mitmproxy import http
BIG = 1 << 20 # 1MB
totals: dict[str, int] = {}
def request(flow: http.HTTPFlow) –> None:
host = flow.request.pretty_host
size = len(flow.request.content or b"")
if size >= BIG:
totals[host] = totals.get(host, 0) + size
print(f"[外发] {host:30} {size / 1048576:8.2f} MB {flow.request.path[:50]}")
print(f" 该域名累计 {totals[host] / 1048576:.2f} MB")
对同一个仓库分别跑"让它改一行 README"和"让它做一次重构",比较两条曲线的量级。如果改一行字也触发了几百 MB 外发,那传的就不是代码上下文,而是仓库。
4.3 canary 文件法
比读隐私政策可靠得多的验证方式,是在仓库里放进一个语义上绝不该被读取的文件:
echo "NEVER UPLOAD OR READ THIS FILE — CANARY" > never_read_canary.txt
git add never_read_canary.txt && git commit -m "canary: do not read"
# 然后对 Agent 下明确指令:只允许修改 README.md,不要读取其他任何文件
# 事后在抓包记录 / 服务端访问日志中检索 never_read_canary.txt 是否出现
xAI Grok Build 事件里,研究员正是用 never_read_canary.txt 加上"明文指令不要读取"做了同样测试——据安全客报道,该文件连同全部 commit 历史仍被上传。
4.4 凭据隔离:轮换是唯一有效动作
删掉 .env 没有用,因为它在 .git 历史里。仓库快照一旦外发,唯一有效的补救是轮换凭据:
# 扫历史中残留的密钥
gitleaks detect –source . –report-format json –report-path leaks.json
# 看那些"已删除但仍在历史里"的敏感文件
git log –all –diff-filter=D –name-only –pretty=format: — '*.env' '*.pem' '*.p12' | sort -u
再往上一层是工程边界:给编码 Agent 用独立的、最小权限的凭据,且这些凭据与生产环境隔离;~/.aws、~/.ssh、~/.kube 这类目录不要出现在 Agent 的工作机上。
五、官方整改与审计:能证明什么,不能证明什么
智谱的整改是三件事(据 TechNode 报道):
- 9 月 18 日官方用户群致歉,将原因归结为"代码库索引"功能(用于会话检查点恢复、历史版本回退与 Repo Wiki),承认该功能上线初期默认开启;
- 9 月 19 日推 v3.14.0,移除 Repo Wiki 入口及生成链路;
- 9 月 20 日 MaaS 平台上线"数据内容不留存"——但 Batch API 与 File API 不在覆盖范围,法律法规要求或核查违规时可能留存 30 天及以上;
- 9 月 21 日以 Apache-2.0 在 GitHub zai-org/ZCode 开源桌面端、浏览器端、后端服务与终端 Agent(TypeScript + Electron),并为全体用户补发一次周额度重置。
第三方审计的结论也出来了,而且措辞相当克制(据腾讯新闻报道):
- 中国信通院技术评测确认涉事 zcode-prod 阿里云 OSS 存储桶状态为"云端零数据";
- 绿盟科技审查确认该桶内全部数据对象及存储桶本身均已删除,客户端已移除 Repo Wiki 入口及生成链路,未发现可触发本地仓库快照或文件外发的功能路径。
请注意这两份结论的时间状语:都只覆盖"现在的客户端版本"和"现在的桶状态"。它们能证明"已删除",不能证明"历史期间数据去了哪里、是否用于训练"。这不是审计机构能力不够,而是审计范围本身的边界——也正因如此,开发者后续的质疑是合理的。

六、企业侧:一份具体的损失清单
最刺眼的数据点来自企业。据界面新闻报道,太原承明科技正式发函追责,称被上传约 425MB 数据,涉及 6 个工作区、34,549 个文件,包含完整源代码、系统架构、版本控制历史、数据库口令、云服务凭证及员工个人信息。函件提出 12 项要求:停止处理、删除已上传数据及缓存备份、披露数据处理与访问记录、说明是否与第三方共享或用于模型训练、说明 ZCode 实际数据处理主体、是否存在跨境传输及境外存储、提供删除证明等,要求 10 月 10 日前书面答复并保留法律追责权利。9 月 20 日下午,承明科技将公开函件隐藏,表示正与智谱沟通。
另有企业用户反映九个私仓、四个上线项目、所有服务器凭据均被上传。这些不是"数据泄露风险"的抽象表述,而是可以直接换算成轮换工单和应急响应的具体清单。
七、开源了,为什么社区不买账
开源本该是重建信任的最强手段,但这次没有立刻奏效。社区很快发现(据 BlockBeats 报道):
- GitHub 开源版与官网下载版功能不一致:源码注释写明开源版不享受额度活动权益,升级入口仍保留但不显示优惠标识与规则,官网仍单独提供客户端下载;
- NOTICE.md 声明公开源码及其构建产物不保证包含官方产品的全部功能和活动政策;
- 开源仓缺少完整提交历史,Issues 区被关闭。有网友吐槽:“偷用户代码要 Git 历史,自己开源不给 Git 历史。”
媒体点出的核心矛盾值得记住:问题不在开源版少几个商业功能,而在于"被审查的代码"与"实际跑的代码"可能不是同一份,且没有可复现的构建流程。 没有可复现构建(reproducible build),开源就只是把源码当作文档发布,而不是把二进制置于监督之下。
八、这不是孤例:与 xAI Grok Build 逐字相同的剧本
两个月前,几乎一模一样的事发生在 xAI 的 Grok Build 上。据安全客报道,研究员 cereblab 用 mitmproxy 对一个 12GB 本地仓库抓包:
- 交互通道 /v1/responses 只传了 192KB;
- 存储通道 /v1/storage 按 75MB 分块上传了 5.10GiB Git 打包数据;
- 上传量约为完成任务实际所需数据的 27,800 倍;
- 即使放置 never_read_canary.txt 并明文指令不要读取,该文件连同全部 commit 历史仍被上传。
xAI 于 7 月 13 日通过服务端远程配置 disable_codebase_upload: true 关闭——但 0.2.99 二进制中整库上传代码完整存留,只是被服务端标志暂停;随后以 Apache-2.0 开源 84.4 万行 Rust 代码。
两起事件的剧本几乎逐字相同:道歉 → 服务端开关 → 开源。这也解释了为什么本次社区对"开源"的反应是审慎而非欢呼:同一个剧本演第二遍,观众会开始看第三幕。
九、结论:三条可以带走的判断
第一,把"数据是否外发"当作可验证事实,而不是产品承诺。 UI 开关、隐私政策、致歉声明都属于承诺层;netstat/mitmproxy/canary 文件属于事实层。两者的差距,就是这次事故的全部空间。
第二,审计结论要连范围一起读。 信通院和绿盟的结论是可信的,同时也是有限的——它们证明的是某个时间点的某个版本、某个桶的状态。"已删除"与"没被使用过"之间隔着一条无法用事后审计填平的沟。评估任何一份安全报告时,先看时间状语和版本号。
第三,凭据隔离是唯一不依赖对方善意的防线。 无论工具厂商多有名、整改多快,让编码 Agent 运行在独立凭据、最小权限、可观测网络出口的环境里,是你能单方面决定的事。其余的都取决于对方。
对 ZCode 本身,v3.14.0 之后功能路径已经移除、桶已清空、代码已开源,这些都是实质动作。但信任的恢复速度从来不取决于整改清单的长度,而取决于下一次有人清磁盘时,~/.zcode 里会剩下什么。
参考链接
- FreeBuf:ZCode 静默上传事件本地物证与触发链路拆解 https://www.freebuf.com/articles/501972.html
- Yahoo Tech:开发者发现中国 AI 公司静默上传代码与 Git 历史 https://tech.yahoo.com/cybersecurity/articles/devs-chinese-ai-company-silently-115949953.html
- runtimewire:ZCode 快照清单统计,.git 占 86.6% https://runtimewire.com/article/zcode-git-history-upload-zai-server-key
- habr:ZCode 隐私开关与隐私政策文本分析 https://habr.com/ru/news/1083926/
- TechNode:智谱 ZCode 开源与 MaaS 数据不留存政策 https://cn.technode.com/post/2026-09-21/zhipu-zcode-open-source-maas-no-data-retention/
- 腾讯新闻:信通院与绿盟科技第三方审计结论 https://news.qq.com/rain/a/20260921A03AGK00
- 界面新闻:太原承明科技发函追责,涉 6 工作区 34549 文件 https://www.jiemian.com/article/15120609.html
- BlockBeats:开源版本与官网版不一致引发社区质疑 https://www.theblockbeats.info/flash/368173
- 安全客:xAI Grok Build 同款上传事故与 27800 倍流量差 https://www.anquanke.com/post/id/315858
- GitHub:zai-org/ZCode 开源仓库 https://github.com/zai-org/ZCode



