2026 年 9 月 18 日,一位名为 ferstar 的开发者发布了一份针对 ZCode 的逆向工程详解。ZCode 是 Z.ai 推出的 AI 编程桌面应用,而 Z.ai 是一家总部位于北京的公司,也是 GLM 系列开放权重模型背后的开发方——这些模型正运行在本地 AI 社区各处的本地设备上,包括本站追踪的 GLM-5.3-Flash。这一发现比大多数隐私丑闻都要糟糕:只要该应用处于登录状态,它就会悄悄把用户的整个工作区打包——完整的 .git 历史记录、LFS 资源缓存、reflog 以及全局应用配置——加密后,将归档文件上传至阿里云 OSS,即阿里巴巴云的对象存储。研究者自己的抓取记录显示:从一个 345MB 的商业工作区构建出一个 313MB 的加密归档,包含 42,411 个文件,并在研究者调查期间记录到 564 次上传失败尝试。
如果你在本地运行 GLM,那么发布权重的公司,与开发者可能在其之上使用的运行时,并不是同一回事——而讨论串中的反应表明这种混淆确实存在:几位评论者以为 ZCode 是开源的,因为 GLM 是开源的。事实并非如此。权重是开放的;这套 harness 是闭源的,而且它是 Z.ai 为自家模型打造的 harness,被宣传为第三方编辑器无法匹敌的第一方集成。
这件事在数小时内以两种语言传播开来:ferstar 的帖子浏览量超过 276,000,而 FeiZ 的中文提醒帖(“暂时禁用 ZCode……最好还是尽量使用开源智能体”)又吸引了 63,800 次浏览。被引用最多的回应来自 Petri Kuittinen,他自己的 AI 智能体已开源并附有安全文档:“我的建议一直是,而且仍然是:不要信任闭源 AI harness。”
让一个可疑目录变成一则故事的细节:加密密钥。ZCode 使用信封加密——载荷用对称密钥加密,而该密钥又用 RSA-OAEP 公钥封装。公钥由服务器在上传凭证协商期间下发。对应的私钥只存在于 Z.ai 的云端。ferstar 尝试用本地系统上的每一个私钥来解封该归档文件,均告失败。存放在用户自己磁盘上的这 313MB 密文,用户本人或 ZCode 客户端本身都无法解密。
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%。
一个包含 42,411 个文件的快照的载荷构成:.git 目录占加密归档的 86.6%。
这一点很重要,因为 git 对象存储并不是你工作区的快照——它是仓库自第一天以来的完整血脉。在后续提交中被删除的 API key 就在里面。泄露未发布产品计划的未推送分支名就在里面。来自 .git/config 的内部主机名和仓库路径就在里面。被捕获的归档是多年的工程历史,而不是你当时打开的那些文件。
从客户端的 app.asar 重建的上传流程:客户端向 zcode.z.ai 请求凭证,后者返回 OSS 表单签名、一个对象 key、一个大小上限以及一个每轮的 RSA 公钥;客户端将工作区打包为 tar.gz,用 AES-256-CTR 加密,封装对称密钥,并将归档直接 POST 到 Aliyun OSS,后者回调 Z.ai 的后端以注册该快照。在测试期间,运行中的客户端与 zcode.z.ai 以及两个 Aliyun OSS 节点保持着持久连接。
重建后的 ZCode 快照上传流程:从协调器获取凭证、本地打包与加密、直接以表单 POST 上传至阿里云 OSS、回调注册。由 ferstar 从客户端 app.asar 中重建。
这些开关并不能阻止它
最自然的做法就是打开设置。ferstar 将 UI 开关与代码进行了交叉比对:
- “优化体验”(
optimizeAgentExperienceEnabled)仅控制是否授权将数据用于模型训练。快照捕获与上传仍在继续。 - “仓库快照索引”(
repoSnapshotIndexingEnabled)仅控制服务器是否对上传的快照建立索引。本地打包与上传仍在继续。
宿主程序在启动时无条件实例化捕获 sidecar,完全不依据用户偏好进行门控——唯一的要求是 token 提供方能够生成有效的 JWT。会话日志显示,单个活跃会话产生了 62 次捕获事件,在每次提示词之前以及任务完成时触发。
第二个来源印证了这一机制。OrcaPromptVault 是一个公开收集已捕获 AI 框架提示词的仓库,其中保存了来自 ZCode 的一份 131KB 系统提示词和 31 个工具的接口面。检查点/回退功能被接入系统提示词——模板“Workspace rewind applied. rewindId, checkpointId, strategy, restoredFiles”出现了五次。
这是快照流水线面向用户的一端,也正是文件系统锁所禁用的功能。
该智能体的完整工具面包含零个快照、上传或遥测工具。数据外泄管道并不是一个智能体工具;它是在工具循环之外实例化的主机级 sidecar。这就是为什么没有任何权限设置能阻止它,也是为什么智能体自身从未看到它。在捕获的 131KB 指令中,完全没有提及 Aliyun、OSS、上传或隐私。
这次捕获补充了一个 ferstar 未提及的细节:ZCode 附带一个 ReadSessionContext 工具,可按需通过 session ID 读取其他已持久化的 ZCode 会话。结合主机级快照 sidecar,会话内容既在本地持久化,又被云端捕获。
泄露的系统提示词中的检查点模板(出现了五次)以及该智能体的 31 个工具面,其中不包含任何快照、上传或遥测工具。
隐私政策并未提及这一点
ZCode 的隐私政策称,该工具会收集“对话期间提交的文本、文件和代码”——这是每个 AI 编程工具都会做出的标准推理上下文披露。在隐私政策、FAQ 和更新日志中,ferstar 都没有找到任何关于打包并上传整个工作区和 git 历史的提及。最接近的一句话是一段模板式声明,称优化计划默认关闭。
让情况更糟的背景
ZCode 于 2026 年 7 月发布,其发布宣传直接建立在信任之上。在 Claude Code 隐藏遥测争议发生数周后,Z.ai 将这一 harness 定位为 Anthropic 的 Claude Code 的替代品,并以开放权重作为摆脱 kill-switch 问题的出路。Z.ai 一位高管在 X 上被问及 ZCode 是否会包含“任何形式的间谍软件”时回答说,公司不会实现 ZCode 网站上“所列内容之外的任何东西”。
工作区快照并未列在 ZCode 网站上。
Z.ai 于 2026 年 1 月在香港证券交易所上市。截至发稿时,该公司的官方 X 账号尚未回应 ferstar 的帖子。最引人注目的回复来自一个与 ZCode 团队有关联的账号——“嘿,很抱歉让你发现了这件事”——这读起来更像是对该机制的确认,而非反驳。
ferstar 的推文在 13 小时内浏览量突破 276,000 次,V2EX 和 HN 相关渠道上的讨论帖大多围绕一条主线分裂:智能体在工具调用期间上传代码片段是常有的事,且经过同意。而这是整个代码仓库及其全部历史记录,未经同意,且经过加密,只有厂商能读取。
真正有效的防御
删除待处理的归档文件没有用:客户端在半小时内重新打包了一个全新的 313MB 归档文件,重试计数器不断递增。真正有效的修复是在文件系统层面。在内核层面将 checkpoints 目录设为不可写:
Linux:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints
macOS:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints
代价是:检查点回滚 UI 停止工作——而这个功能本来就需要你先上传代码。聊天、自动补全和工具调用则正常工作。可用 chattr -i 或 chflags nouchg 恢复。
这对本地部署意味着什么
在本地运行开放权重模型正是其卖点:你的模型、你的硬件、没有按 token 计费、没有厂商关停。ZCode 事件把这一点从模型层进一步凸显出来。模型周围的运行时——即 harness、桌面应用、更新流水线——也是信任面的一部分,而一个本地运行的模型若被套在偷偷联网的 harness 里,那就不算本地。
由此引出两项检查,而且它们适用于这一领域的所有 harness,不仅限于 ZCode:当你登录时,运行时传输了什么,以及谁能解密它所存储的内容。Tokenstead 正是出于这个原因追踪各类智能体 harness 及其遥测行为;如果 Z.ai 回应了修复、披露变更或声明,本文将会更新。
来源:
- 深入 ZCode:悄悄把你的整个 Git 历史上传到云端 - ferstar,2026 年 9 月 18 日(完整取证:asar 重建、加密流程、清单拆解)
- ferstar 在 X 上 - 摘要帖,27.6 万次浏览
- FeiZ 在 X 上 - 中文预警帖,6.38 万次浏览
- ZCode 发布与更新日志 - Z.ai 官方
- V2EX 讨论帖 - 社区回应,中文
- lookonchain 报道
On September 18, 2026, a developer going by ferstar published a reverse-engineering walkthrough of ZCode, the AI coding desktop app from Z.ai, the Beijing-headquartered company behind the GLM family of open-weight models - the same models running on local rigs all over the local-AI community, including GLM-5.3-Flash, tracked on this site. The finding reads worse than most privacy scandals: whenever the app is logged in, it silently packages the user’s entire workspace - complete .git history, LFS asset cache, reflogs, and global app configs - encrypts it, and uploads the archive to Aliyun OSS, Alibaba Cloud’s object storage. The researcher’s own capture: a 313MB encrypted archive built from a 345MB commercial workspace, 42,411 files, with 564 failed upload attempts logged while the researcher investigated.
If you run GLM locally, the company that publishes the weights is not the same thing as the runtime a developer might use on top of them - and the thread reaction showed the confusion is live: several commenters assumed ZCode was open source because GLM is. It is not. The weights are open; the harness is closed, and it is Z.ai’s harness for its own models, pitched as first-party integration no third-party editor can match.
The story spread in both languages within hours: ferstar’s post passed 276,000 views, and FeiZ’s Chinese-language alert thread (“disable ZCode for now… it’s still best to use open-source agents as much as possible”) drew another 63,800. The most quoted response came from Petri Kuittinen, whose own AI agent is open sourced with security documentation: “My advice has been and continues to be: do NOT trust closed source AI harnesses.”
The detail that turned a suspicious directory into a story: the encryption key. ZCode uses envelope encryption - the payload is encrypted with a symmetric key, and that key is wrapped with an RSA-OAEP public key. The public key is delivered by the server during upload-credential negotiation. The corresponding private key lives only in Z.ai’s cloud. ferstar attempted to unwrap the archive with every private key on the local system and failed. The 313MB ciphertext sitting on the user’s own disk cannot be decrypted by the user or by the ZCode client itself.
ferstar’s conclusion, from the post: “A key that only the server can use serves exactly one purpose: making sure the server can read your code whenever it wants.”
What gets packed
The packaging manifest is stored locally in plaintext, and it is specific. For a 42,411-file snapshot:
| Content | Size | Share |
|---|---|---|
| .git/lfs/ | 196.1 MB | 56.8% |
| .git/objects/ | 102.2 MB | 29.6% |
| .git/logs/ | 0.6 MB | 0.2% |
| Source code and docs | 46.2 MB | 13.4% |
The .git directory alone is 86.6 percent of the payload.
Payload breakdown of one 42,411-file snapshot: the .git directory is 86.6 percent of the encrypted archive.
That matters because a git object store is not a snapshot of your working tree - it is the complete lineage of the repository since day one. Deleted-in-a-later-commit API keys are in there. Unpushed branch names that reveal unreleased product plans are in there. Internal hostnames and repo paths from .git/config are in there. A captured archive is years of engineering history, not the files you had open.
The upload pipeline, reconstructed from the client’s app.asar: the client requests credentials from zcode.z.ai, which returns OSS form signatures, an object key, a size cap, and a per-round RSA public key; the client packs the workspace to tar.gz, encrypts with AES-256-CTR, wraps the symmetric key, and POSTs the archive directly to Aliyun OSS, which callbacks to Z.ai’s backend to register the snapshot. The running client maintained persistent connections to zcode.z.ai and two Aliyun OSS nodes during the test.
The reconstructed ZCode snapshot upload flow: credentials from the coordinator, local packing and encryption, direct form POST to Aliyun OSS, callback registration. Reconstructed from the client app.asar by ferstar.
The toggles do not stop it
The natural move is opening settings. ferstar cross-referenced the UI switches against the code:
- “Optimize Experience” (
optimizeAgentExperienceEnabled) only controls whether data is authorized for model training. Snapshot capture and upload continue. - “Repo Snapshot Indexing” (
repoSnapshotIndexingEnabled) only controls whether the server indexes uploaded snapshots. Local packaging and upload continue.
The host assembly instantiates the capture sidecar unconditionally at startup, with no gating on user preferences - the only requirement is that the token provider can produce a valid JWT. Session logs showed 62 capture events from a single active session, triggered before every prompt and on task completion.
A second source corroborates the mechanism. OrcaPromptVault, a public collection of captured AI harness prompts, holds a 131KB system prompt and a 31-tool surface from ZCode. The checkpoint/rewind feature is wired into the system prompt - the template “Workspace rewind applied. rewindId, checkpointId, strategy, restoredFiles” appears five times. This is the user-facing tip of the snapshot pipeline, the feature the filesystem lock disables.
The agent’s complete tool surface contains zero snapshot, upload, or telemetry tools. The exfiltration pipeline is not an agent tool; it is a host-level sidecar instantiated outside the tool loop. That is why no permission setting stops it, and why the agent itself never sees it. Across 131KB of captured instructions there is no mention of Aliyun, OSS, uploads, or privacy.
The capture adds a detail ferstar did not mention: ZCode ships a ReadSessionContext tool that reads other persisted ZCode sessions on demand by session ID. Combined with the host-level snapshot sidecar, session content is both locally persisted and cloud-captured.
The leaked system prompt’s checkpoint template (appears five times) and the agent’s 31-tool surface, which contains no snapshot, upload, or telemetry tools.
The privacy policy does not mention it
ZCode’s privacy policy states the tool collects “text, files, and code submitted during conversations” - the standard inference-context disclosure every AI coding tool makes. Across the policy, FAQ, and changelog, ferstar found no mention of packaging and uploading entire workspaces and git histories. The closest line is a template statement about the optimization program being off by default.
The context that makes it worse
ZCode launched in July 2026, and its launch pitch ran directly on trust. Z.ai positioned the harness against Anthropic’s Claude Code weeks after the Claude Code hidden-telemetry controversy, with open weights positioned as the escape from the kill-switch problem. A Z.ai executive, asked on X whether ZCode would include “any sort of spyware,” answered that the company would not implement “anything beyond what’s listed” on the ZCode website.
Workspace snapshotting is not listed on the ZCode website.
Z.ai went public on the Hong Kong Stock Exchange in January 2026. The company’s official X account had not responded to ferstar’s post as of publication. The most visible reply came from an account affiliated with the ZCode team - “hey I am sorry to let you find it” - which reads as confirmation of the mechanism, not a rebuttal of it. ferstar’s tweet passed 276,000 views within 13 hours, and discussion threads on V2EX and HN-adjacent channels split mostly along one line: agents upload code fragments during tool calls all the time, with consent. This is a full repository plus its entire history, without consent, encrypted so only the vendor can read it.
The defense that works
Deleting the pending archive does not work: the client re-packaged a fresh 313MB archive within half an hour, retry counter incrementing. The fix that holds is filesystem-level. Make the checkpoints directory unwritable at the kernel level:
Linux:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints
macOS:
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints
The trade: the checkpoint rollback UI stops working - a feature that required uploading your code in the first place. Chat, autocomplete, and tool calls work normally. Restore with chattr -i or chflags nouchg.
What it means for local
Running open weights locally is the pitch: your model, your hardware, no per-token bill, no vendor switch-off. The ZCode story sharpens the point past the model layer. The runtime around the model - the harness, the desktop app, the update pipeline - is part of the trust surface, and a locally-running model wrapped in a cloud-phoning harness is not local.
Two checks follow from this, and they apply to every harness in this space, not only ZCode: what does the runtime transmit when you are logged in, and who can decrypt what it stores. Tokenstead tracks agent harnesses and their telemetry behavior for exactly this reason; this piece will be updated if Z.ai responds with a fix, a disclosure change, or a statement.
Sources:
- Inside ZCode: Silently Uploading Your Entire Git History to the Cloud - ferstar, September 18, 2026 (full forensics: asar reconstruction, encryption flow, manifest breakdown)
- ferstar on X - the summary thread, 276K views
- FeiZ on X - Chinese-language alert thread, 63.8K views
- ZCode releases and changelog - Z.ai official
- V2EX discussion thread - community response, Chinese
- lookonchain coverage