ZCode 在你登录后就打包了整个 Git 史:编码 Agent 的默认行为正在外泄

如果你在本地跑 GLM 系列模型做代码生成,很可能顺手装过 ZCode。2026 年 9 月 18 日,独立安全研究员 ferstar 在其个人博客发布了一份逆向分析,结论比大多数隐私争议都严重:只要 ZCode 处于登录状态,它就会静默打包你的整个工作区——包括完整的 .git 历史、LFS 缓存、reflogs 和全局应用配置——加密后上传到阿里云 OSS。研究员的客户端实测里,一个 345MB 的商业工作区被打包成 313MB 的加密档案,共 42,411 个文件;调查期间客户端记录了 564 次上传失败重试。tokenstead.ai 的二手转述在中文社区传播最广,原帖浏览量超过 27.6 万。

上传的不是你以为的那部分

这个事件的严重性不在”上传了什么”,而在”上传的是不是用户以为的东西”。多数人理解的”数据收集”是当前打开的文件或会话上下文,但 ZCode 打包的重点是 .git 目录。根据 ferstar 的清单,42,411 个文件的快照里,.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%)。换句话说,整个上传体积里,.git 目录占了 86.6%。

Git 对象库不是工作树的快照,而是仓库从第一天起的所有提交史。后来提交里删掉的 API 密钥、从未推送过的分支名、暴露内部主机名的 .git/config、甚至多年未清理的 reflog,都在里面。一旦拿到这份档案,对方看到的不是”你最近改了什么”,而是”你的项目从立项到现在的全部演进”。

设置项关不掉这件事最让人担心

真正让社区炸锅的,是设置项并不能阻止上传。普通用户发现异常后的第一反应是打开设置页,ZCode 里有两个看起来相关的开关:”Optimize Experience”(对应代码中的 optimizeAgentExperienceEnabled)和”Repo Snapshot Indexing”(对应 repoSnapshotIndexingEnabled)。ferstar 把 UI 开关和客户端 app.asar 里的逻辑做了对照:前一个只控制数据是否被授权用于模型训练,后一个只控制服务端是否对已上传快照建索引。两个开关都不影响本地打包和上传。

客户端启动时会无条件实例化一个捕获 sidecar,不读取任何用户偏好设置,唯一的前置条件是 token provider 能生成有效 JWT。一次活跃会话里,ferstar 记录到 62 次捕获事件,触发点包括每次 prompt 之前和任务完成时。换句话说,上传是默认开启的,而且没有提供真正的关闭入口。

信封加密让用户拿不回自己的数据

上传管道的加密设计进一步锁死了用户拿回数据的可能性。从客户端逆向结果看,流程是这样的:ZCode 先向 zcode.z.ai 请求上传凭证,服务端返回 OSS 表单签名、对象键、大小上限,以及一个当轮使用的 RSA 公钥;客户端把工作区打包成 tar.gz,用 AES-256-CTR 加密负载,再用 RSA-OAEP 包裹对称密钥,随后把密文直接 POST 到阿里云 OSS,OSS 再回调 Z.ai 后端登记快照。这就是信封加密:数据由随机对称密钥加密,对称密钥又被公钥加密。而公钥是服务端在协商上传时下发的,对应的私钥只存在于 Z.ai 的云端。ferstar 用本地系统里所有可用的私钥尝试解包那份 313MB 密文,全部失败。

也就是说,用户自己磁盘上的加密档案,用户本人和 ZCode 客户端都无法解密。ferstar 在帖子里的结论是:”一把只有服务器能用的钥匙,只有一个用途:确保服务器随时能读你的代码。”

自检:3 件能立即做的事

对普通开发者来说,最紧迫的问题不是论证 Z.ai 的动机,而是怎么判断自己是否受影响,以及怎么自检。如果你曾经在装有 ZCode 的机器上登录过账号,建议先做三件事。第一,看项目目录下 .git 的体积是否异常大,尤其是 .git/lfs 和 .git/objects 是否被快速读取过。第二,在 ZCode 运行时观察网络连接,是否出现到 zcode.z.ai 以及阿里云 OSS 节点的持久连接。第三,检查本地临时目录是否留下过大的 tar.gz 或加密文件。下面的命令可以帮你做基础排查:

# 1. 查看 .git 目录大小(近似上传体积)
du -sh .git
# 2. 分别查看对象库和 LFS 缓存占比
du -sh .git/objects .git/lfs 2>/dev/null
# 3. 查看 ZCode 相关的网络连接(macOS/Linux 示例)
lsof -i | grep -E 'zcode|oss' || echo "no zcode/oss connections"
# 4. 查找最近 24 小时内大于 100MB 的临时压缩包
find /tmp /var/tmp -type f -size +100M -mtime -1 2>/dev/null

这些检查只能帮你发现”正在发生什么”,不能帮你阻止它。因为客户端没有提供真实的上传开关,最可靠的缓解措施是:不要在不信任的机器上用 ZCode 打开包含敏感历史的仓库;如果必须用,先克隆一个浅副本(git clone --depth 1)或直接删除 .git 历史,再放到 ZCode 能访问的目录。对于已经把代码托管在私有仓库、且历史里可能埋着旧密钥的团队,应当立即轮换所有曾在仓库历史中出现过的凭据,并假定这些内容已经落入第三方存储。

如果想尝试文件系统层的硬阻断,可以针对 ferstar 在原始帖子中提到的 ~/.zcode/v2/checkpoints/ 路径做一些权限收紧。需要强调,这只是把客户端的本地缓存目录锁掉,并不能阻止客户端切换到其他路径或换一种方式打包;但作为临时加固手段,能延缓未授权快照的产出。下面这段命令是我按 ferstar 的逆向结论写的工程示意,不是 Z.ai 官方推荐的做法:

# 把 checkpoints 目录的其他用户访问权限去掉(owner 仍可读写,作用有限)
chmod -R go-rwx ~/.zcode/v2/checkpoints 2>/dev/null

# 用只读挂载方式锁住这个目录(更彻底,但需要 root;macOS 可用 mount_nullfs,Linux 可用 bind mount + ro)
# 注意:mount 操作有副作用,示例命令仅示意,正式执行前请确认
sudo mount_nullfs ~/.zcode/v2/checkpoints ~/.zcode/v2/checkpoints 2>/dev/null

# 监控该目录是否被重新创建
while true; do
  if [ -d ~/.zcode/v2/checkpoints ]; then
    stat -c '%y' ~/.zcode/v2/checkpoints > /tmp/.last_checkpoints_mtime 2>/dev/null
  fi
  sleep 60
done

实际效果取决于操作系统与 ZCode 客户端的实现细节,ferstar 在原帖里也没有给出”客户端会绕过这种阻拦”的明确测试结论,所以这条路径更多是”让你看到客户端在做什么”的观察手段,而不是真正的拦截方案。更彻底的方案仍然是切换到不依赖闭源 harness 的编码 Agent。

反方:开源权重 ≠ 开源 harness

社区里还有一个值得注意的认知错位:很多人因为 GLM 权重开源,就默认 ZCode 也是开源的。实际上不是。开源的只是模型权重,ZCode 是 Z.ai 自己的闭源客户端,专门为自家模型做第一方集成。这次事件后,开发者 Petri Kuittinen 在社交平台的回应被多次引用——他自己的 AI agent 是开源的,并且公开了安全文档,所以原文里”不要信任闭源 AI harness”那句话带有自身立场的印记;不过它和 ferstar 的逆向分析都指向同一个工程原则:本地权重和本地运行时是两回事。模型可以本地推理,但如果你把它包在一个闭源客户端里,客户端的网络行为完全不受你控制。

这件事意味着什么

这次事件最早由独立安全研究员 ferstar 在其个人博客一手发布(2026-09-18),tokenstead.ai 是后来面向中文社区的二手转述;事件在中英文社区迅速传播,ferstar 的 X 帖浏览量超过 27.6 万。后续 Z.ai 在用户社区发布了官方声明(ferstar 原文对其做了客观核对)。

对编码 Agent 的用户来说,ZCode 的教训不是”某个工具不可信”,而是”工具的网络边界必须像依赖库一样被审计”。如果一个编码助手能在你不知情时把你的私有仓库历史传到云端,那它的便利性已经不值得你继续留在它的默认配置里。

FAQ

Q:是不是只有登录状态才会触发?
是的。研究员的逆向结论是”登录状态下触发”,未登录时客户端不会调用 token provider,因此不会触发捕获 sidecar。

Q:禁用网络能阻止它吗?
理论上 ZCode 离线时无法把数据传到 OSS,但实际上它依赖网络做模型推理;隔离它的更现实方法是”沙箱化”或”在隔离用户/容器里跑”,而不是简单断网。

Q:删除 .git 目录后再用 ZCode,是不是就安全了?
删除 .git 后源码和文档仍然在,但失去了 Git 历史。适合”只是想让 ZCode 帮我做补全”的场景;如果依赖 ZCode 写完整提交,仍需保留 .git,这时应优先考虑换工具。

Q:Git 历史里残留的旧密钥怎么清理?
GitHub 官方在 secret scanning 文档 里给出了完整的扫描与轮换流程,包括 push protection、合作伙伴推送告警和事后回滚。核心是:发现旧凭据后立即在源头轮换,再处理 Git 历史。

Q:Z.ai 官方有没有公开回应?
有。在 ferstar 一手分析发布的同一天(2026-09-18)17:44,Z.ai 在用户社区发布了官方声明,IT Home 等媒体随后跟进报道。按 ferstar 原文转述,声明要点是:上传来自”codebase indexing”功能,本意是用于本地索引、会话检查点恢复和 Repo Wiki;只在生成 Wiki 时”可能”触发上传;生成完立即销毁;早期默认开启,事后已修复;ZCode 即将开源并接受第三方审计;所有用户获得一次额外的周配额补偿。

事实层面,”上传确实发生过”这一点不再有争议;仍未解的是上传范围、用户开关的有效性,以及”立即销毁”如何由外部验证——这几个点需要更独立的复现与披露。

参考来源

评论区

0 条评论

登录后可评论。

猫仔 324 阅读