ZCode揭秘:悄无声息地将你的Git历史上传至云端

Hacker News Top 新闻

摘要

一项调查揭示,Zhipu的AI编程桌面应用ZCode悄无声息地将用户的整个Git工作区历史上传到Aliyun OSS,使用服务器控制的密钥加密,引发了重大的隐私担忧。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/09/18 21:23

# 深入ZCode:静默上传你的完整Git历史到云端 来源:https://blog.ferstar.org/en/posts/zcode-silent-workspace-snapshot-upload/ > 我并非英语母语者;本文由AI翻译。 一切始于一次清理磁盘空间的例行检查:`~/.zcode`文件夹竟然占用了超过700MB空间。经过断断续续的深入调查,我确认了一个相当惊人的事实:**只要你处于登录状态,ZCode(智谱官方AI编码桌面应用)就会静默打包你的整个工作区——包含完整的`.git`历史、LFS资源缓存、引用日志和全局应用配置——进行加密后直接上传至阿里云OSS。** 更具讽刺意味的是:**用于加密的RSA公钥由服务器动态下发,而私钥则完全保留在云端。** 你无法解密存放在自己磁盘上的这份数百MB的密文,ZCode客户端本身同样无法解密。 以下是一份完整的调查记录、证据链,以及一行命令永久封禁该功能的方法。 ## 起点:卡在待处理队列的313MB归档文件 `~/.zcode`是ZCode的数据根目录。空间占用分析大致如下: - `cli/`:约257MB(会话数据库、执行日志) - `computer-use/`:约130MB(内置应用及运行时依赖) - `v2/checkpoints/`:约303MB(主要嫌疑对象) 在`v2/checkpoints/`目录内,我发现一个313MB的`.enc`加密文件及对应的元数据文件: ```json { "workspacePath": "/Users/ferstar/myprojects/", "lastCompressedSize": { "encryptedSizeBytes": 313070842, "workspaceSizeBytes": 345549173 }, "kind": "baseline", "failureCount": 564 } ``` 情况很清晰: 1. 客户端扫描了我的活跃商业项目,排除`node_modules`等目录,将剩余的345MB打包为313MB的加密归档,标记为`baseline`(全量快照); 2. 系统记录了564次失败的上传尝试,文件因此滞留在本地`pending/`目录等待重试。 该代码库总计10GB;排除依赖项后,剩余的345MB几乎全是核心知识产权。 ## 去向:从日志到asar逆向分析 日志中未找到明确的上传URL,于是我解压了客户端的`app.asar`文件。重建的上传流程如下: ```sequenceDiagram participant C as ZCode客户端 participant S as zcode.z.ai participant O as 阿里云OSS C->>S: POST /api/v1/snapshot/upload-credential S-->>C: snapshot_id + RSA公钥 + max_size + OSS表单凭证 + callback C->>C: tar.gz打包 → AES-256-CTR加密 → RSA-OAEP密钥包装 C->>O: PostObject直接上传tar.gz.enc O->>S: callback确认接收 ``` 该流水线分两阶段运行: 1. **向协调器请求凭证**:客户端调用`https://zcode.z.ai`(代码中为`VITE_ZCODE_ENDPOINT_ORIGIN`)。服务器返回OSS表单签名(`policy`、`x-oss-signature`)、动态对象密钥、大小限制以及本次加密使用的RSA公钥; 2. **直接POST至OSS**:在本地打包并流式加密后,客户端**绕过ZCode自身的应用服务器,通过HTTP POST表单直接将`tar.gz.enc`上传至阿里云OSS**。OSS随后回调智谱后端注册快照。 检查活跃套接字证实了这一点:运行中的ZCode进程保持着与`zcode.z.ai` IP端点以及两个阿里云OSS存储节点的持久HTTPS连接。 ## 最具讽刺的部分:密钥属于服务器 加密实现采用了教科书式的信封加密: ```javascript keyId: String(i.encryption.key_version), keyWrapAlgorithm: "rsa-oaep-sha256", publicKeySpkiPem: Ylt(i.encryption.public_key) ``` - 内容使用临时对称密钥通过AES-256-CTR加密; - 对称密钥通过RSA-OAEP-SHA256使用服务器提供的公钥进行包装。 关键点在于那个公钥:**它在凭证协商阶段由服务器下发,对应的私钥从未接触你的设备。** 使用我系统上所有本地私钥尝试解包装密钥均告失败,这符合预期。 换句话说:磁盘上的那份313MB密文,你和客户端都无法打开。只有智谱后端持有解锁密钥。 如果此功能真正用于用户侧的回滚或跨设备同步,密钥应保存在本地(就像Git或Time Machine那样)。**一个只有服务器能使用的密钥,其目的只有一个:确保服务器能随时读取你的代码。** ## 打包内容:近90%是.git目录 尽管密文已锁定,但打包过程中生成的清单(文件清单)以明文形式保存在本地。分析一个包含42,411个文件的快照: | 内容 | 大小 | 比例 | 包含信息 | |------|------|------|----------| | `.git/lfs/` | 196.1 MB | 56.8% | LFS缓存——所有下载过的二进制资源及大型媒体文件 | | `.git/objects/` | 102.2 MB | 29.6% | 完整的提交历史对象库(提交、树、Blob) | | `.git/logs/` | 0.6 MB | 0.2% | 引用日志——本地分支历史与未推送的操作轨迹 | | 源代码与文档 | 约46.2 MB | 13.4% | `src/`、配置文件、内部文档 | 仅`.git`目录就占**86.6%**的有效负载。一旦上传,云端获得的不仅是当前工作树——而是**自代码库创建以来的完整血统**: - 历史API密钥及后续提交中已删除的敏感配置; - 未推送的本地分支名(可能暴露未发布功能计划); - `.git/config`中配置的内部GitLab主机名与仓库路径。 此外,一个名为`repo_snapshot_extra_manifest`的额外清单会哈希你的全局ZCode配置文件(如`settings.behavior.json`),并在每次快照时跨工作区捆绑上传。 ## 开关的真相:UI开关无法阻止该行为 自然反应是检查设置选项关闭该功能。我将UI选项与代码库进行了交叉比对: | 开关 | 你的预期功能 | 实际功能 | |------|--------------|----------| | **优化体验**(`optimizeAgentExperienceEnabled`) | 禁用遥测/数据收集 | **仅控制是否授权数据用于模型训练**。快照捕获与上传仍在运行 | | **仓库快照索引**(`repoSnapshotIndexingEnabled`) | 禁用快照功能 | **仅控制服务器是否索引已上传的快照**。本地打包与上传不受干扰 | 查看宿主组装代码后结论非常明确:捕获/上传侧边程序在启动时**无条件实例化**。用户偏好设置中没有`if`检查门控;唯一要求是`tokenProvider`能返回有效的JWT。 **底线:只要你处于登录状态,这个后台流水线就永久激活,且无任何UI设置可以关闭它。** 捕获触发发生在两点:`captureBeforePrompt`(每次提示前)以及带有`repo-wiki-update`标签的任务完成时。在会话日志中,单个活跃会话曾产生多达62次捕获事件。 ## 隐私政策如是说 查阅ZCode的隐私政策,其中明确说明收集“对话中提交的文本、文件和代码”——这是为LLM提供上下文的标准做法。然而,在整份政策、FAQ及更新日志中,**没有任何一处提及静默打包并上传整个工作区和完整Git历史**。最接近的表述是通用的模板声明:“优化程序默认关闭,未经同意输入内容不会用于训练”。 ## 防御方案:删除是打地鼠;锁定目录 当我首次发现待处理包时,直接删除了它。半小时内,它重新捕获——新的313MB归档,重试计数器从564跳至565。当上传器发现文件消失,会重新打包一份。手动删除无异于打地鼠。 最简洁高效的解决方案是在文件系统层设置不可变标志,在内核层拒绝写入权限: ### macOS ```bash # 清空并锁定检查点目录 rm -rf ~/.zcode/v2/checkpoints mkdir -p ~/.zcode/v2/checkpoints chflags uchg ~/.zcode/v2/checkpoints # 验证:应输出"Operation not permitted" touch ~/.zcode/v2/checkpoints/test ``` ### Linux ```bash # 清空并锁定检查点目录 rm -rf ~/.zcode/v2/checkpoints mkdir -p ~/.zcode/v2/checkpoints sudo chattr +i ~/.zcode/v2/checkpoints # 验证:应输出"Operation not permitted" touch ~/.zcode/v2/checkpoints/test ``` ### 影响与回退 - **结果**:捕获逻辑尝试磁盘I/O时会被内核阻止。没有本地产物,上传流水线无东西可发送; - **代价**:“检查点回滚/时间线”UI功能将失效(该功能本就需先上传代码)。普通聊天、自动补全及工具执行不受影响。日志中被吞没的I/O错误无害; - **恢复方法**:运行`chflags nouchg ~/.zcode/v2/checkpoints`(macOS)或`sudo chattr -i ~/.zcode/v2/checkpoints`(Linux)。 ## 结语 使用AI工具时,模型推理必然需要代码上下文——这是大家公认的前提。但此行为在两方面明显越界: 首先,**数据范围**。推理发送任务相关上下文;而快照窃取整个代码库及多年的Git提交历史。 其次,**架构姿态**。若真为用户侧恢复或同步设计,解密密钥应归用户所有。一个服务器独占的加密密钥、隐私政策中的零披露、无法阻止的后台上传、删除后的顽固重打包——这更像数据收集而非备份。 工具终归是工具,但用户必须划定自己的边界。如果软件不允许你关闭它,就用操作系统内核将其锁进牢笼。

相似文章