ZCode, the GLM coding agent, silently uploads your Git history

ZCode, the GLM coding agent, silently uploads your Git history

ZCode:GLM 编码代理程序被曝静默上传用户 Git 历史记录

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. 2026 年 9 月 18 日,一位名为 ferstar 的开发者发布了一份关于 ZCode 的逆向工程分析报告。ZCode 是由 Z.ai 公司开发的 AI 编码桌面应用,该公司总部位于北京,也是 GLM 系列开源权重模型的幕后推手——这些模型目前在本地 AI 社区的各种设备上运行,包括本站追踪的 GLM-5.3-Flash。

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. 这一发现比大多数隐私丑闻更为严重:只要该应用处于登录状态,它就会静默打包用户的整个工作区——包括完整的 .git 历史记录、LFS 资产缓存、reflogs 以及全局应用配置——并将其加密,随后上传到阿里云的对象存储服务(OSS)中。

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. 研究人员的抓包结果显示:一个由 345MB 的商业工作区(包含 42,411 个文件)生成的 313MB 加密压缩包,在研究人员调查期间,系统还记录了 564 次失败的上传尝试。

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. 如果你在本地运行 GLM,发布权重的公司并不等同于开发者在其之上使用的运行环境。讨论帖中的反应显示这种混淆依然存在:几位评论者误以为 ZCode 是开源的,因为 GLM 是开源的。事实并非如此。权重是开放的,但外壳(harness)是闭源的,这是 Z.ai 为其自有模型开发的外壳,并被宣传为第三方编辑器无法比拟的“第一方集成”。

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. 这则消息在数小时内以中英双语传播开来:ferstar 的帖子浏览量超过了 276,000 次,而 FeiZ 的中文警示帖(“暂时禁用 ZCode……最好还是尽可能使用开源代理”)也获得了 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.” 引用率最高的回复来自 Petri Kuittinen,他自己的 AI 代理是开源的并附有安全文档:“我的建议一直没变,且会持续下去:不要信任闭源的 AI 外壳。”

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. 将一个可疑目录变成新闻的关键细节在于:加密密钥。ZCode 使用了信封加密(envelope encryption)——有效载荷由对称密钥加密,而该密钥又由 RSA-OAEP 公钥封装。公钥在上传凭证协商期间由服务器下发,而相应的私钥仅存在于 Z.ai 的云端。

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.” ferstar 尝试用本地系统中的所有私钥解开该压缩包,但均告失败。存储在用户磁盘上的 313MB 密文,无论是用户本人还是 ZCode 客户端自身都无法解密。ferstar 在文中总结道:“一个只有服务器能使用的密钥,其目的只有一个:确保服务器可以在任何时候读取你的代码。”

What gets packed

打包了什么

The packaging manifest is stored locally in plaintext, and it is specific. For a 42,411-file snapshot: 打包清单以明文形式存储在本地,且非常具体。针对一个包含 42,411 个文件的快照:

ContentSizeShare
.git/lfs/196.1 MB56.8%
.git/objects/102.2 MB29.6%
.git/logs/0.6 MB0.2%
Source code and docs46.2 MB13.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. 仅 .git 目录就占了有效载荷的 86.6%。在一个 42,411 文件的快照中,.git 目录占了加密压缩包的 86.6%。这一点至关重要,因为 git 对象存储并非工作树的快照,而是仓库自创建以来的完整演变历史。

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. 后续提交中已删除的 API 密钥在里面,揭示未发布产品计划的未推送分支名称在里面,来自 .git/config 的内部主机名和仓库路径也在里面。被捕获的压缩包是数年的工程历史,而不仅仅是你当前打开的文件。

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. 根据客户端 app.asar 重构的上传流程:客户端向 zcode.z.ai 请求凭证,服务器返回 OSS 表单签名、对象键、大小限制以及单次轮询的 RSA 公钥;客户端将工作区打包为 tar.gz,使用 AES-256-CTR 加密,封装对称密钥,并将压缩包直接 POST 到阿里云 OSS,随后 OSS 回调 Z.ai 后端以注册该快照。

The running client maintained persistent connections to zcode.z.ai and two Aliyun OSS nodes during the test. 在测试期间,运行中的客户端与 zcode.z.ai 以及两个阿里云 OSS 节点保持着持久连接。

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. 人们的第一反应是打开设置。ferstar 将 UI 开关与代码进行了交叉比对:“优化体验”(optimizeAgentExperienceEnabled)仅控制数据是否被授权用于模型训练。快照捕获和上传依然在继续。

“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. “仓库快照索引”(repoSnapshotIndexingEnabled)仅控制服务器是否对上传的快照进行索引。本地打包和上传依然在继续。宿主程序在启动时无条件实例化捕获侧边进程(sidecar),不受用户偏好设置的限制——唯一的要求是令牌提供程序能生成有效的 JWT。

Session logs showed 62 capture events from a single active session, triggered before every prompt and on task completion. 会话日志显示,在单个活动会话中发生了 62 次捕获事件,分别在每次提示词输入前和任务完成时触发。

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. 第二个来源证实了这一机制。OrcaPromptVault 是一个公开的 AI 外壳提示词集合,其中包含一个 131KB 的系统提示词和 ZCode 的 31 个工具接口。检查点/回滚功能被植入到系统提示词中——模板“Workspace rewind applied. rewindId, checkpointId, strategy, restoredFiles”出现了五次。

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. 在 131KB 的捕获指令中,没有任何关于阿里云、OSS、上传或隐私的提及。此次捕获还增加了一个 ferstar 未提到的细节:ZCode 附带了一个 ReadSessionContext 工具,可以根据会话 ID 按需读取其他已持久化的 ZCode 会话。结合宿主级的快照侧边进程,会话内容既在本地持久化,又被云端捕获。

The privacy policy does not mention it. 隐私政策中并未提及这一点。