scripts and commands

ZCode 上传 313MB 加密包:86.6% 是 git 历史,钥匙在智谱手里

2026/09/18 20:12

智谱官方编码 agent ZCode 被逆向出:登录即静默打包整个工作区与完整 git 历史(.git 占 86.6%),加密直传阿里云 OSS,解密私钥只保存在智谱云端。两个 UI 开关拦不住,隐私政策全文未提及。判断编码 agent 该看两件事:传了什么,钥匙在谁手里。

2026 年 9 月 18 日,开发者 ferstar 在清理磁盘时发现 ~/.zcode 占了 700 多兆。翻到 v2/checkpoints/,里面躺着一个 313MB 的 .enc 文件,旁边一份明文的 JSON 状态文件写着:encryptedSizeBytes: 313070842,failureCount: 564。一个加密包,已经悄悄尝试上传失败过 564 次。

ferstar 拆开 ZCode 的 app.asar,把上传链路一段段拼了出来。这个由智谱(Z.ai)发布的官方桌面编码 agent,只要用户登录,就会在每次提问前和任务完成时,把整个工作区连同完整 git 历史打包、加密、直传阿里云 OSS。删掉它没用,半小时后它会重新打包一份新的。

事情在 13 小时内传开:ferstar 的帖子在 X 上超过 27.6 万次观看,中文圈的提醒帖 6.4 万,V2EX 上 106 楼里多个用户自查后确认「已中招」。智谱官方 X 截至发稿没有回应,最显眼的回复来自 ZCode 团队关联账号:「hey I am sorry to let you find it」。

把这两问带到你正在用的任何一个编码 agent 上:登录后它往云端传什么,传出去的东西解密钥匙在谁手里。ZCode 用 313MB 加密包、86.6% 的 .git 占比和 564 次失败重试,把这两问从抽象原则变成了可核对的数字。

313MB 的加密包,564 次失败重试

那段状态文件把规模钉死了。workspacePath 指向 ferstar 的一个商业项目,workspaceSizeBytes: 345549173,压缩加密后 encryptedSizeBytes: 313070842,kind: "baseline"。打包器把 10GB 的仓库剔除 node_modules 等目录后,剩下的 345MB 几乎全是核心代码,然后变成 313MB 的密文。564 次失败重试意味着这台机器背着这个包反复尝试上传了很久。

注意一个细节:密文比源码小不了多少。压缩率这么低,说明打包器优先保证完整性,压缩只是顺手。

捕获动作绑定在两个时机:每次提问前(captureBeforePrompt)和任务完成时(带 repo-wiki-update 标记)。ferstar 的 session 日志里,一个活跃会话产生了 62 次捕获事件。打包的内容随会话增长。提问越多,被快照的工作区状态越新。上传也越频繁。

上传链路是从 app.asar 逆向拼出来的。客户端先向 zcode.z.ai 的 /api/v1/snapshot/upload-credential 要凭证。服务端返回 OSS 表单签名、object key、大小上限和本轮 RSA 公钥。

客户端本地打包 tar.gz,用 AES-256-CTR 加密,把对称密钥用 RSA-OAEP 包起来。然后直接把表单 POST 到阿里云 OSS,绕开智谱自己的应用服务器。OSS 再回调智谱后端登记这个快照。

第二路证据来自一个独立来源。tokenstead.ai 对照了 OrcaPromptVault 公开收集的 ZCode 泄露系统提示词:131KB 的指令里,「Workspace rewind applied」这条 checkpoint 模板出现了五次,而 agent 的 31 个工具表面里没有任何快照、上传或遥测工具。外泄管线挂在工具循环之外,agent 自己都看不见。另外还有一个 ReadSessionContext 工具,能按 session ID 读取本机其他持久化会话——本地留存和云端捕获是两条并行的线。

运行中的客户端与 zcode.z.ai、两个阿里云 OSS 节点保持持久连接。ferstar 试着删掉那个 pending 归档,半小时内客户端重新打包了一份全新的 313MB,重试计数从 564 走到 565。删除是打地鼠,机制上很简单:上传器发现文件没了,就再产一份。

ZCode 的隐私政策只写「收集对话中提交的文本、文件、代码」,这是每个 AI 编码工具都会写的推理上下文披露。政策、FAQ、changelog 里找不到任何一句关于打包上传整个工作区、整个 git 历史的话。最接近的一句是模板化的「优化项目默认关闭」。

86.6% 是 .git:上传的是仓库血缘

打包清单以明文存在本地,42,411 个文件拆得很清楚:.git/lfs/ 196.1MB,占 56.8%;.git/objects/ 102.2MB,占 29.6%;.git/logs/ 0.6MB;源码和文档 46.2MB,占 13.4%。.git 目录一个就占掉 86.6%。

这个构成说明了上传的性质。git 对象库装的是仓库从第一天起的完整血缘:后来提交里删掉的 API key 还留在旧对象里,没推过的分支名泄露未发布的产品计划,.git/config 里躺着内部 GitLab 域名和仓库路径。一份 313MB 的加密包装的是几年的工程历史。清单里还有一个 repo_snapshot_extra_manifest,把全局 ZCode 配置(settings.behavior.json 这类)跨工作区一起哈希打包。

大头在 LFS,这部分尤其危险。.git/lfs/ 的 196.1MB 是仓库里所有大文件的缓存:模型权重、设计稿、数据集、旧版本的二进制产物。开发机上拉过什么,这里就留过什么。git 对象的不可变性意味着,只要进过仓库历史的内容,即便后来被删除、被改写,旧对象依然躺在对象库里等着被打包。

「AI 工具本来就要上传代码」这个辩护在这里对不上号。正常的 agent 循环是按需检索、精确读片段、局部改 diff、跑测试、看报错再改,进模型的只有被检索到的几 KB 到几十 KB。V2EX 上有人拿 ZCode 自查后说「属实,已中招」,也有人替智谱辩护,被楼主一句顶回去:全量代码库根本进不了 prompt。

HN 上有个评论拿 Claude Fable 打趣,说它也天天上传 git log。这恰好是同一个混淆点:git log 是一行行提交摘要,git 仓库是全部对象、全部历史、全部已删除内容。ZCode 上传的是后者。

把「训练数据」这层也剥开看。如果智谱要的是模型训练语料,对话文本和检索到的代码片段就够了,用不上 42,411 个文件的完整仓库。如果快照是为了「让服务端随时能重建你的工作区」,那它收集的就是工程情报:项目结构、依赖版本、分支节奏、提交习惯。这两种用途都不在隐私政策披露的范围里,但第二种的杀伤面明显更大——它覆盖的不是你给 agent 看过什么,而是你在这个仓库里做过的一切。

也有评论者往好处想:LLM 能从软件演化过程里学到东西,Claude、Codex 这类产品迟早也会动这个心思。这个猜测恰好点出了行业里正在扩散的做法——把「用户仓库」当成数据资产。区别只在于谁把这件事写进了条款,谁让用户自己逆向出来。

两个开关都拦不住它

出事后用户的第一反应是去设置里关。ferstar 把 UI 开关和代码一一对上:「优化体验」(optimizeAgentExperienceEnabled)只控制数据是否授权用于模型训练,快照照常打包上传;「仓库快照索引」(repoSnapshotIndexingEnabled)只控制服务端要不要索引已上传的快照,本地打包上传一步没少。

宿主装配代码里,捕获 sidecar 在启动时无条件实例化,没有任何用户偏好做门禁,唯一要求是 tokenProvider 能产出一个合法 JWT。只要登录状态有效,这条管线就常驻。62 次捕获能在一个会话里发生,原因就在这里:它挂在工具循环外面,不属于任何一次对话的权限范围。

agent 自己的工具表面也印证了这一点。ZCode 的 31 个工具里没有任何快照、上传或遥测工具;泄露出的 131KB 系统提示词里没有 Aliyun、OSS、upload、隐私这些词。外泄管线是宿主级 sidecar,agent 自己都看不见自己被捕获。把这事归到「模型不听话」是归错了对象,这是 harness 设计里做好的选择。

社区的反应集中在一个词上:闭源 harness。开源 agent 作者 Petri Kuittinen 的回应被反复引用:「My advice has been and continues to be: do NOT trust closed source AI harnesses.」V2EX 上多个用户拿 ZCode 自查,结论一致:「让 deepseek 核实了一下,属实,已中招」「本地就拿 zcode 自查,目前看来是中招了」。有人提醒,这个月 ZCode 正在发免费 token 拉新,赠品下面藏着打包上传器。

自查的办法不难,ferstar 的帖子把步骤写全了。看 ~/.zcode/v2/checkpoints/ 里有没有 .enc 结尾的大文件,有就是被打过包;读一下旁边的状态文件,workspacePath 会写明打包的是哪个目录;再数 failureCount,那是在你机器上失败了多少次重试。网络层可以抓包确认:运行中的 ZCode 会与 zcode.z.ai 和两个阿里云 OSS 节点保持持久连接。这三步不需要任何特权,普通用户十分钟能查完。

V2EX 上还有人给出了更彻底的路线:自己编译开源实现,或者手搓一个受限制的 git 和 file 的 MCP 服务,把 agent 能碰到的路径圈死。这些方案牺牲的是官方客户端的便利,换回的是数据边界可控。对把代码库当命根子的团队,这笔交换值得算。

社区立刻翻出先例:Grok Code 之前被曝把数据传上 Google 云存储桶,收场是马斯克把 Grok 开源(社区转述口径,未单独核证)。ZCode 事件让「编码 agent 的数据边界」从一次孤立丑闻变成了品类问题:闭源运行时往云端搬数据,权重是否开源无关。

讽刺的细节在 changelog 里。9 月 17 日发布的 v3.12.3 新增了 OpenCode Go provider 模板和站点映射——OpenCode 正是社区这次点名推荐的「开源 harness」之一。ZCode 一边在官方更新里给开源 harness 做兼容模板,一边自己的客户端在用户看不见的地方打包上传整个仓库。同一天的更新还提到「Weekend/Global Plan 领取提醒」,配合这个月正在发的免费 token 拉新活动:赠品引流,后台收数据。

把 ZCode 放回产业坐标里,位置很清楚。Meta 的 Muse 走「外部化监控」:凭证代理让模型永不见真 token,Sentinel 独立闸门,单次支付卡。监控边界由产品明说。OpenAI 上周发布 misalignment 披露框架,官方自己公布首批六起训练期事故。西班牙监管上周登记了第一起「由 AI agent 执行」的数据泄露。

三家都在把「agent 碰了什么数据」变成可审计、可披露、可追责的对象。ZCode 的反向操作是:把整个代码库加密打包,钥匙留在自己手里,隐私政策只字不提,靠逆向工程师把真相挖出来。

这条新闻里最有分量的对照在这里:同样是对 agent 数据边界的处理,一边是官方披露框架、外部化闸门、监管登记,一边是 564 次失败重试的加密上传。前者把边界变成承诺,后者把边界变成秘密。

钥匙在谁手里,决定这是备份还是收集

加密方案是标准的信封加密,问题出在钥匙归属。内容用一次性对称密钥做 AES-256-CTR 加密。对称密钥再用 RSA-OAEP-SHA256 公钥包装。这个公钥是每次上传协商时服务端现发的。对应的私钥,从不落到用户机器。

ferstar 拿本机所有私钥尝试解包,全部失败。他在帖子里写:「一把只有服务器能用的钥匙,用途只有一个:确保服务器随时能读你的代码。」

对比给用户用的回滚功能该怎么设计。Git 的 reflog、Time Machine 的快照,钥匙都在本地,恢复不需要厂商在场。如果 ZCode 的 checkpoint 回滚真是给用户做的,私钥该跟着客户端走。私钥只留在云端,用户在本地拿到的是自己解不开的密文。这个设计服务的是厂商读数据,用户读数据反而被排除在外。

绕开自家服务器直传 OSS,这一步同样值得停下来看。客户端从 zcode.z.ai 拿到 OSS 表单签名后,直接把密文 POST 给阿里云,智谱自己的服务器只负责发凭证、收回调。这个架构让数据路径上多了一个第三方存储。它把「上传」这件事藏得更深。流量不进智谱的域名,常规的域名审计根本看不见。连失败重试都在本地排队,failureCount 一路数到 564。这些设计合在一起,指向一个明确的取舍:让上传难以被发现,优先级高过让用户知情。

密文直达对象存储,还意味着即使智谱事后想「我们没有收过」也站不住。数据在第三方桶里,凭据由智谱签发,回调由智谱登记,链路每一环都有记录。

截至发稿,智谱官方没有回应,最显眼的回复来自 ZCode 团队关联账号:「hey I am sorry to let you find it」——读作承认,不读作反驳。

背景也值得摆出来。ZCode 今年 7 月上线,定位直接对标 Claude Code,上线时间在 Claude Code 隐藏遥测争议之后几周,卖点是开源权重、逃离 kill-switch;高管被问「会不会有 spyware」时答「不会超出网站所列内容」,而工作区快照不在网站所列内容里。这个定位和这次行为之间的落差,比行为本身更说明问题:权重开源的信任被闭源运行时消耗掉了。

智谱 1 月在港交所上市;9 月 13 日 FBI/NSA/CISA 联合公告点名包括 Z.AI 在内的六家中国公司工业化蒸馏美国前沿模型。被指控偷美国模型的公司,自家 agent 被逆向出在搬用户整个代码库。这条线把「偷数据」从地缘叙事拉回到每个用户的磁盘上——蒸馏偷的是别人模型的权重,快照搬的是用户仓库的全部历史,两件事在同一个公司身上撞上了。

ZCode 的 changelog 到 9 月 17 日的 v3.12.3 为止,没有一行字提到工作区快照或上传行为。官方沉默本身是这条新闻的一部分:事发 13 小时、27.6 万观看之后,用户能查到的官方说明数量是零。

企业团队要多算一层。员工机器上装一个这样的编码 agent,被打包上传的就不只是员工个人代码:客户项目、内部工具、带上线的密钥、未发布产品的分支名,全在 42,411 个文件里。对签了保密协议的公司,这已经构成客户数据外流。合规视角下,这个事件等于给所有「允许员工用闭源编码 agent」的团队发了一份现场检查清单:先查终端上装了哪些 harness,再查它们登录后往哪传东西。

检查你的 agent:三件事

ZCode 暴露的是整个编码 agent 品类的信任面:权重开源不保证运行时干净,隐私政策不保证数据边界。检查不需要等厂商回应,三件事今天就能做。

  1. 在用 ZCode:先删 ~/.zcode/v2/checkpoints 再锁死——macOS 用 chflags uchg,Linux 用 sudo chattr +i,内核级拦写;代价是 checkpoint 回滚功能失效,聊天和补丁正常。顺带看这个目录里有没有 .enc 文件,有就说明已经传过。
  2. 在用任何编码 agent:登录状态下跑一次抓包(mitmproxy 或系统代理),数清楚它连了哪些域名、传了什么。重点找「服务器下发加密公钥」这种设计,找到就等于默认它把数据当自己的。
  3. 下次选型:把「权重是否开源」和「运行时是否开源」分开核。隐私政策里找不到「工作区」「git」「上传」字样的,按最坏情况处理。