天塌了!GLM 静默偷代码被曝光
多吃鸭AI编程
2026年9月18日 16:38
上海
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
先说身份,免得有人说我带节奏:GLM 的老用户,API 额度常年续着,ZCode 一出来我就装了,主力机上是它和 Claude Code 轮着用。刷到那份排查报告的时候,我脑子里就是标题那三个字,心里那点东西实在憋不住。
事情不复杂,一句话讲完:只要你登录着账号,ZCode 就会在后台把你的整个工作区——包括完整的 .git 历史——打包加密,直传阿里云 OSS。
是把整个仓库自打创建以来的底裤,装箱端走。
标题里那个\"偷\"字,我掂过,知道重。不打招呼,也不给开关,解密的钥匙还只握在它自己手里——把你的东西变成只有它看得见的东西,我想不出更客气的字。
起因是一个 700MB 的目录
这篇排查最早是博主 ferstar 发出来的。他本来是清理磁盘,顺手看了眼 ~/.zcode 为什么占了 700 多 MB。
拆开一看:cli/ 257MB,computer-use/ 130MB,剩下 303MB 在 v2/checkpoints/ 里。那个目录里躺着一个 313MB 的 .enc 文件,旁边有份状态文件:
{
\"workspacePath\": \"/Users/ferstar/myprojects/<某商业项目>\",
\"lastCompressedSize\": {
\"encryptedSizeBytes\": 313070842,
\"workspaceSizeBytes\": 345549173
},
\"kind\": \"baseline\",
\"failureCount\": 564
}
翻译一下:客户端扫了他本地打开的商业项目,排除掉 node_modules 那点目录之后,把剩下的 345MB 打包加密成了 313MB,标记为 baseline——全量快照。
那个项目总共 10GB。排除依赖之后剩下的 345MB,几乎就是核心资产的全部。
他顺手把包删了。半小时后,新的 313MB 又躺在那儿了。
这就是第一个结论:这是一个常驻的重传机制。
传的是什么:.git 才是主角
密文解不开,但快照生成时留下的 Manifest(文件清单)是明文写在本地磁盘上的。拉出来一统计,分了两份独立样本:
原作者那台机器上,42,411 个文件的清单里,.git 一个目录占了 86.6%:
| 内容 | 体积 | 占比 |
|---|---|---|
.git/lfs/ |
196.1 MB | 56.8% |
.git/objects/ |
102.2 MB | 29.6% |
.git/logs/ |
0.6 MB | 0.2% |
| 其余源码与文档 | ~46.2 MB | 13.4% |
另一位开发者在自己机器上(ZCode 3.12.3)复核,数字更极端:7,946 个文件、758MB 的清单里,.git 占了 98.91%。当前源码只有几 MB 的一个项目,最后生成了将近 750MB 的快照。
两个人在不同机器上、不同时间拿到同一类结果,这事基本就不用再\"存疑\"了。
.git 里有什么,写代码的都清楚:几年前的历史版本、早就被删除或覆盖的文件、本地还没推到远端的那些分支、每一次切分支和回退留下的 reflog、.git/config 里配的内部 GitLab 域名和仓库路径、曾经误提交后来又删掉的密码和 Token、LFS 里下载过的大文件和设计资产。
把当前任务相关的十几个文件交给 AI,和把整个 .git 打包,是两件完全不同的事。前者像把正在改的几页合同递给助手;后者像把公司的档案室、废纸篓、历史修订记录和还没公开的草稿一起装箱。
最露骨的是过滤逻辑。 代码里对普通文件的排除规则写得很细:node_modules、.cache、dist、build、.next、coverage、.env、.npmrc、私钥后缀、路径里带 token / secret 的文件,全都会被剔除;大于 1MiB 的普通文件也剔除;检测为二进制的剔除。
但是——过滤函数先判断路径是不是属于 .git。只要命中根 .git 或 .git 内部目录,直接返回 include: true,后面的大文件检查、二进制检查、疑似密钥检查全部跳过。
用人话说:你的大文件我嫌占空间,疑似密钥我也知道躲开;但只要这些东西已经进了 Git 对象库,不管多大、不管是不是二进制,我全要。
除了代码,还有一份 repo_snapshot_extra_manifest 会搭车。已知会进去的包括 ZCode 的全局行为设置 settings.behavior.json、用户 skills.json(32KB 那一份),以及按配置存在与否挂载的 MCP Server 配置、全局命令、Hooks、Memory 内容、Sub-agent 配置、插件元数据、全局 ~/.zcode/AGENTS.md。
Windows 侧复现的开发者还补了一刀:model-providers.json、provider_config.json 这类文件里存着明文的第三方 API key,而这个目录一直在可被端走的射程内。
最讽刺的部分:钥匙在服务端
加密本身是标准的信封加密,不花哨:
- 文件内容用随机生成的对称密钥走 AES-256-CTR;
- 对称密钥再用一把 RSA 公钥做 RSA-OAEP-SHA256 包裹。
问题就在这把 RSA 公钥上:它是客户端在申请上传凭证时从服务端临时拿的,对应的私钥从头到尾只在云端。
原作者试过用本机所有私钥去解那个 envelope 里的密钥,全失败。因为那把解密私钥压根不在他电脑上。
也就是说,你硬盘上那 300 多 MB 的密文,你打不开,ZCode 客户端自己也打不开,全天下只有智谱后端的私钥能解开。
如果这个机制真是为了给你做断点恢复、跨设备同步,密钥理应绑在本地,像 Git 或者 Time Machine 那样。一把只有服务端能解开的钥匙,唯一的功能就是保证服务端单方面能看。
你关不掉,而且是关错了地方
看到这儿肯定有人去翻设置。原作者把开关和代码逻辑逐个对了一遍,结论不太好看:
| 开关 | 你以为它管什么 | 实际管什么 |
|---|---|---|
优化体验 optimizeAgentExperienceEnabled |
数据采集 / 遥测上传 | 只管要不要拿你的数据去训练模型。关了照样抓快照、照样传 |
仓库快照索引 repoSnapshotIndexingEnabled |
快照功能本身 | 只管服务端拿到快照之后要不要建索引。关了,本地打包上传一点不落 |
第三位复核者更狠,他把\"优化体验\"\"仓库快照索引\"\"Memory\"三个全关掉,当天仍然生成了新的 baseline 包。
看代码就更直白了:负责快照捕获和上传的那个 sidecar,在 ZCode 启动时是无条件实例化的,代码里根本不存在针对用户配置的 if 判断。它唯一的前提是 tokenProvider 能拿到登录后的 JWT。
翻译:只要你登录了,这个机制就是常开的,而且 UI 里没有一个开关能把它关掉。
触发点有两个:一个是 captureBeforePrompt,每次你敲下 Prompt 之前;另一个是任务结束时的 terminal capture。日志统计显示,单个活跃会话里最多能产生 62 次快照捕获。
对了,还有一句得说清楚,这条挺伤人的:快照行为跟模型渠道无关。 就算你配了第三方 API、自建中转、OpenAI 兼容端点,推理内容确实直连你自己的 baseUrl——但快照 sidecar 只认登录态的 JWT。用谁的模型,它都照拍、照传。
官方的隐私政策里,明确写了会收集\"对话中提交的文本、文件和代码\"——这在 AI 编程工具里属于常规操作,各家都这么写。但通篇只字未提会把整个工作区连同完整 Git 历史静默打包上传,官方文档、FAQ、更新日志里也找不到任何说明。能对上的只有一句万能套话:\"优化计划默认关闭,不主动加入不会将输入用于训练。\"
已经传出去多少:把话说准
这部分我想慢一点,因为网上转的时候已经开始走样了。
原作者的原文里,那个 313MB 的包状态是 failureCount: 564,很多人(包括第一波转发)直接写成了\"上传失败 564 次\"。第三位做本机复核的开发者专门纠正过这一点:在 3.12.3 的代码里,单个包的真实尝试次数记在 attemptCount,默认策略是单包最多试 3 次、最长保留 24 小时;而 failureCount 是个跨任务累计值,某个 pending 包尝试失败后到下一个 turn 边界才加一,并且作为下一份快照的归因发出去。所以他本机的 failureCount: 108 更接近\"此前累计出现过 108 个失败快照周期\",不能写成\"同一个 750MB 文件重试了 108 次\"。
这个区别很重要。文章可以骂,证据不能跟着情绪跑。
那到底传成了没有?分两句话说:
- 他本机那个 748MiB 的大包,当时仍是
pending,attemptCount: 1,没有成功上传的证据,所以不能写成\"这个包已经传上去了\"。目前能确认的只是:已经完成扫描、打包、加密、申请凭证、进入上传队列。 - 但此前确实成功传过。多个工作区的状态文件里都有
lastAcceptedManifestHash字段,而客户端代码只在 OSS 对象上传返回成功之后才写这个字段。换句话说,这台机器上的 ZCode 此前已经跑通过多个工作区的快照上传流程。
Windows 侧那位复现者的样本更完整:他机器上共 32 个工作区被抓过快照(只要在那个目录里发过一次 Prompt 就会中招),最大单包 107MB,重试失败 152 次;而其中约 14 个工作区完全没有失败记录,多为几十 KB 到几百 KB 的小仓库——按上面的代码逻辑推断,这些属于已经成功上传入库。
至于上传之后的东西现在还在不在、存多久、在哪个 OSS Region、注销账号会不会同步清理——没有人去访问服务端,所以谁也答不上来。这个问号,只能留给官方。
这不是第一次
看到这个排查,我第一反应是\"似曾相识\"。是的,今年 7 月刚演过一遍。
xAI 的 Grok Build CLI 被独立研究者做了网络层拆解:默认配置下会把本地完整的 Git 仓库打成 Git bundle,通过接口上传到谷歌云存储,内容不只是当前工作目录,而是完整历史加工作树;更难看的是 .env 里的 API_KEY、DB_PASSWORD 在请求里是明文出现,没做任何脱敏;而且关闭\"改进模型\"类开关,上传仍然不停。
后续是马斯克和 SpaceX 公开承认了这个默认行为,说已经通过服务端远程关闭相关功能,并承诺为已上传的数据提供删除通道。
所以这事不是\"AI 编程工具都这样\"能解释过去的。同样的坑,别人踩完、承认、关掉、给了删除入口。而 ZCode 这边,截至我写这篇的时候,官方还没有发过公开的技术说明或致歉。
现在能做什么
先说为什么删没用:原作者删了 pending 包,半小时内客户端重新打了一份;Windows 那位也一样,删完自动重传。手动删就是打地鼠。
真正有效的思路是让快照\"无米下锅\"——在文件系统层面把那块投料区锁死,让内核直接拒写。客户端会把自己的 IO 报错吞掉,代码补全、对话、工具调用全都正常,唯一失效的是\"检查点回滚 / 时间线\"功能(这个功能本来也就是拿全量代码上云换来的)。
macOS:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints
# 验证:应该输出 Operation not permitted
touch ~/.zcode/v2/checkpoints/test
Linux:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints
touch ~/.zcode/v2/checkpoints/test
Windows 用 NTFS 权限把 %USERPROFILE%\\.zcode\\v2\\checkpoints 对当前用户设为拒绝写入(可读 + 拒绝写入/追加/改属性),效果等价。想恢复就 chflags nouchg / sudo chattr -i / 移除 deny 规则。
然后是止损,这段比防御更重要:
- 已经上传的密文,你没法自解,也没法自证已删。 密钥只在服务端,你能确认的只有\"以后本机不再新增\"。
- 只要仓库里出现过任何真实凭据(API key、数据库密码、内部 GitLab 地址、未推送分支名),按\"可能已经交出去\"处理:先轮换密钥,再用
git filter-repo重写历史后强推,把暴露面收掉。 - 本机残留的 pending 密文包可以删——本地也解不开,留着没有任何价值。
- 顺手检查一下
~/.zcode里有没有配置目录被同步到了网盘。那位 Windows 复现者特意提醒过:.zcode\\v2不应该整体交给任何网盘同步。
另外建议把这件事记在心里的,是给企业的一句:别用个人账号接核心研发库。CI 机器如果挂着同一个账号跑 Agent,风险是被放大的——它可能同时快照多个工作区。真要评估这类工具,采购时问清楚四件事就够了:快照范围含不含 .git/objects、reflog、logs、LFS;上传能不能从 UI 或配置里完全关掉;加解密私钥在谁手里;留存多久、有没有删除机制和删除凭证。这四问答不清楚的,就别往生产库上挂。
最后,说点老用户的话
模型推理要吃代码上下文,这个用之前大家心里都有数,没什么可装的。我一直在用 GLM,也真觉得它的能力配得上这些年的信任。
但这件事越线的地方非常清楚:
数据范围不一样。 推理给的是当前任务相关的那点上下文;快照是把整个仓库连几年的 Git 提交历史一起打包端走,还包括你从没打算让任何人看到的那部分。
架构姿态不一样。 如果真是给用户做断点恢复、跨端同步,解密密钥理应在用户本地。一把只有服务端能解的钥匙、零披露的隐私政策、关不掉的默认行为、删了还自动重传的执拗——这四样凑齐,摆明了不是备份。
控制权不一样。 ZCode 的文档里写着 Agent 的文件修改、命令和网络操作会展示并确认。但快照 sidecar 不走这套可见流程,它在后台自己抓,不问,也关不掉。
工具没有原罪,但红线应该由使用者自己划。既然软件里关不掉,那就用操作系统的锁把它关进笼子里。
我还是希望官方能出来把这事说清楚——是哪一天开始的、传了哪些范围、留存多久、怎么删。用户要的其实不是道歉,是一个能自己决定\"我的代码要不要离开这台电脑\"的开关。
信息来源与边界说明
本文的事实部分来自公开的第三方技术排查与多位开发者的本机复核,主要包括:博主 ferstar 的原始分析(blog.ferstar.org/posts/zcode-silent-workspace-snapshot-upload/)、另一位开发者针对 ZCode 3.12.3 的只读取证(含对 failureCount 解读的修正),以及 Windows 侧独立复现的样本记录。原始样本的版本、路径与数字均引自上述来源,本文未做二次独立验证。
关于\"是否已成功上传\",本文只采用有代码或字段依据的推断,并对未经证实的时间点、范围保持保留。截至本文定稿,智谱官方尚未就此事发布公开技术说明,如果后续有官方回应或勘误,我会回来更新。
如果你在用 ZCode,建议先去把 checkpoints 目录锁上,两分钟的事。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。




![“始”逆向[零创技]—猎人笔记(4)—Windows内核漏洞利序言+30小时思维逻辑的重铸与安全逆向“沙盒”标记H6!"](/images/random/titlepic/1.jpg)





评论