近日,有开发者在排查 ZCode 本地磁盘占用时,发现了一个值得关注的数据安全问题:
ZCode 疑似会在登录状态下自动创建工作区快照,并将其加密后上传至云端。快照中不仅可能包含当前项目源码,还可能包含完整的
.git目录、Git 历史、LFS 缓存以及部分应用配置。
需要说明的是:以下内容主要来自开发者对 ZCode 客户端、日志及本地文件的逆向分析和实测,并非 ZCode 官方针对该事件发布的说明。
事情是怎么发现的?
开发者最初只是发现:
~/.zcode
目录占用了 700MB 以上空间。
进一步检查后,在:
~/.zcode/v2/checkpoints/
发现了一个体积超过 300MB 的加密文件。
相关状态信息表明,这个文件属于:
baseline
也就是一次完整的工作区基线快照。
原作者测试中的工作区有效内容大约 345MB,加密压缩后的文件约 313MB。
而且由于上传失败,这个文件一直保存在 pending 状态并持续重试。
上传流程是怎样的?
通过分析 ZCode 客户端代码和网络连接,作者还原出的流程大致为:
本地工作区
↓
tar.gz 打包
↓
AES-256-CTR 加密
↓
RSA-OAEP 加密 AES 密钥
↓
获取云端上传凭证
↓
上传至阿里云 OSS
客户端首先向 ZCode 服务端申请上传凭证。
服务端返回包括:
- Snapshot ID
- RSA 公钥
- OSS 上传凭证
- Object Key
- 文件大小限制
- Callback 信息
随后客户端在本地完成压缩和加密,再直接上传到 OSS。
也就是说,大文件本身并不一定经过 ZCode 的业务服务器中转。
一个值得关注的问题:解密密钥在服务端
根据原作者逆向分析,工作区文件使用随机生成的 AES 密钥加密。
随后 AES 密钥再使用:
RSA-OAEP-SHA256
进行封装。
关键在于:
RSA 公钥由服务端动态下发,对应私钥并不保存在用户电脑上。
因此,本地生成的加密快照用户自己实际上无法直接解密。
这种设计本身并不能证明数据被人工查看,但至少意味着:
快照并不是一种只有用户自己才能解密的“零知识备份”。
服务端掌握相应解密能力。
快照里包含什么?
这部分可能才是开发者最需要关注的。
作者检查快照生成过程中留下的 Manifest 文件后发现,其中包含 4 万多个文件。
其测试项目的大致组成如下:
| 内容 | 占比 |
|---|---|
.git/lfs/ |
约 56.8% |
.git/objects/ |
约 29.6% |
.git/logs/ |
约 0.2% |
| 当前源码、配置和文档 | 约 13.4% |
也就是说:
.git 目录占整个快照体积约 86.6%。
这和单纯上传“当前代码上下文”是两个完全不同的概念。
为什么 .git 被上传值得关注?
.git 并不只是一些 Git 配置文件。
例如:
.git/objects/
里面可能包含项目历史中的:
- Commit
- Tree
- Blob
- 历史文件版本
这意味着即使某个敏感文件已经从当前工作区删除,只要它曾经提交进 Git,相关内容仍有可能存在于 Git Objects 中。
另外:
.git/logs/
可能保存 reflog 信息。
而:
.git/config
则可能暴露:
- 内部 GitLab/Gitea 地址
- Repository URL
- 内网域名
- 项目路径
对于公司内部项目而言,这些信息显然比“当前正在编辑的几个文件”敏感得多。
关闭「优化体验」有没有用?
根据原作者对客户端代码的分析:
没有。
ZCode 中与数据相关的一些设置,并不等于“禁止工作区快照上传”。
例如:
优化体验
主要控制用户内容是否被用于产品或模型训练优化。
它和工作区 Snapshot 上传不是同一套逻辑。
仓库快照索引
看起来像是控制快照,但作者分析认为:
它控制的更接近于:
快照上传以后是否建立索引
而不是:
是否生成和上传快照
作者在客户端代码中发现,负责 Snapshot 的 Sidecar 会在程序启动时初始化。
主要前提是:
用户已经登录
并能够获取有效 Token。
什么时候会创建快照?
根据日志和代码分析,至少存在类似:
captureBeforePrompt
这样的触发点。
也就是说:
在发送 Prompt 之前可能创建 Snapshot。
任务结束后也可能触发相关仓库快照操作。
原作者观察到,一个比较活跃的会话可能产生多次 Snapshot 捕获行为。
因此它并不一定只是:
第一次打开项目 → 上传一次
而可能伴随项目使用持续发生。
官方隐私政策怎么写?
ZCode 当前隐私政策确实说明,在使用 AI 辅助功能时可能收集用户在对话过程中提交的:
- 文本
- 文件
- 图片
- 音视频
- 配置参数
- Shell 命令
- 代码
这对于 AI Coding 工具来说并不意外。
因为模型想理解代码,本身就必须获得一定的代码上下文。
但需要区分两个概念:
为了完成当前 Prompt 提交必要上下文
和:
自动打包整个 Workspace + 完整 Git 历史
两者的数据范围差异非常大。
截至原作者调查时,其认为官方文档及隐私说明没有非常明确地向用户解释:
Workspace Snapshot 是否会包含整个
.git历史,以及这一机制具体如何上传和保存。
这也是此次争议最大的地方之一。
Linux 用户如何检查?
如果安装了 ZCode,可以先查看:
du -sh ~/.zcode
然后:
du -sh ~/.zcode/v2/checkpoints
继续检查:
find ~/.zcode/v2/checkpoints -type f -ls
如果发现大量:
.enc
文件或者体积异常大的 Snapshot 文件,就值得进一步检查。
如何阻止 Snapshot 写入?
原作者提供了一种比较直接的方法:
从文件系统层阻止 ZCode 写入 checkpoints 目录。
Linux:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints
验证:
touch ~/.zcode/v2/checkpoints/test
正常情况下会看到类似:
Operation not permitted
这意味着目录已经被设置为 Immutable。
应用程序无法继续往里面创建 Snapshot。
Linux 如何恢复?
执行:
sudo chattr -i ~/.zcode/v2/checkpoints
即可解除锁定。
macOS
macOS 可以使用:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints
解除:
chflags nouchg ~/.zcode/v2/checkpoints
会不会影响 ZCode 正常使用?
按照原作者测试:
代码补全、AI 对话、工具调用等主要功能仍可以正常使用。
但是与 Snapshot 相关的:
Checkpoint / Timeline / 回滚
等能力可能无法正常工作。
所以是否采用这种方式,需要根据自己的使用场景决定。
最值得关注的其实不是「AI 会不会读取代码」
现在使用 Cursor、Claude Code、Codex、ZCode 等 AI Coding 工具,让模型读取部分源码本身并不奇怪。
否则模型也没办法帮你改代码。
真正需要关注的是:
1. 上传范围
读取当前任务相关代码,和上传整个 Git Repository 的历史,是完全不同的数据范围。
尤其:
.git/objects
.git/lfs
.git/logs
.git/config
可能包含大量当前工作区里已经不存在的信息。
2. 用户是否充分知情
如果存在完整仓库 Snapshot,那么应该明确告诉用户:
上传什么
什么时候上传
为什么上传
保存多久
能否关闭
谁能够解密
而不是让用户自己通过几百 MB 的缓存文件才发现。
3. 企业源码风险
对于个人开源项目影响可能相对有限。
但如果你使用 AI Coding 工具打开的是:
- 公司商业源码
- 尚未发布的产品
- 内网项目
- 客户代码
- NDA 项目
- 带有历史密钥的 Git 仓库
那么就应该特别关注 AI Coding 工具到底会扫描和上传哪些内容。
建议
如果正在使用 ZCode 处理商业项目,可以先自行检查:
~/.zcode/v2/checkpoints/
目录。
同时建议所有使用 AI Coding 工具的开发者都养成一个习惯:
不要只关心「AI 会读取哪些代码」,还应该关心「客户端到底会向外发送哪些文件」。
对于企业项目尤其如此。
AI Coding 确实越来越好用,但:
AI 可以理解代码,并不意味着所有历史代码都应该默认离开开发者的电脑。
在官方进一步解释 Snapshot 的用途、范围、保存期限以及关闭机制之前,对于包含商业源码、密钥历史和内部仓库信息的项目,谨慎一些并没有坏处。
来源说明:
本文根据 ferstar 于 2026 年 9 月 18 日发布的《扒一扒 ZCode 静默上传全量 Git 历史的骚操作》进行整理,并结合 ZCode 当前公开隐私政策重新组织内容。
原文属于开发者个人逆向分析及实测结果,相关行为的具体设计目的及服务端数据处理方式,仍应以 ZCode 官方后续说明为准。