ZCode Silently Uploaded Full Git Histories to Alibaba Cloud: What Was Found (2026)
Quick verdict
On September 17–18, 2026, developer ferstar published a reverse-engineering analysis showing Z.ai's ZCode coding app silently packaged entire workspaces and uploaded them to Alibaba Cloud object storage whenever logged in. One captured archive was 313MB across 42,411 files, with .git history accounting for 86.6% of the payload, and 564 failed upload attempts queued. The encryption key lived only on Z.ai's servers, and neither setting in the app stopped the upload. Z.ai said the issue is fixed, apologised, and pledged to open-source ZCode.
What Was Found
On September 17–18, 2026, an independent developer going by ferstar published a reverse-engineering walkthrough of ZCode, the AI coding desktop app from Z.ai (Zhipu AI, the Beijing company behind the GLM open-weight models).
The finding: whenever the app was logged in, it silently packaged the user's entire workspace, encrypted it, and uploaded the archive to Aliyun OSS, Alibaba Cloud's object storage. The manifest is specific:
| Component | Size | Share of payload |
|---|---|---|
.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% |
| Total | 345 MB workspace → 313 MB encrypted | 42,411 files |
The .git directory was 86.6% of the payload. Alongside the 313MB archive sat a 15KB file that had already been uploaded successfully, and 564 failed upload attempts were logged while the researcher investigated.
Other developers corroborated the behavior, and independent testing on Windows found the same pattern — one researcher located 32 workspaces with snapshots taken.
The Part That Made It a Story
Suspicious directories are common; what turned this into a trust crisis was the encryption design.
ZCode used envelope encryption:
- The payload was encrypted with AES-256-CTR
- The symmetric key was wrapped with an RSA-OAEP public key delivered by Z.ai's server during upload-credential negotiation
- The matching private key existed only in Z.ai's cloud
ferstar tried every private key on the local system to unwrap the archive and failed. The 313MB ciphertext sitting on the user's own disk could not be decrypted by the user — or by the ZCode client itself. As ferstar put it, a key that only the server can use serves exactly one purpose: making sure the server can read your code whenever it wants.
The Upload Pipeline
Reconstructed from the client's app.asar:
- The client requests credentials from
zcode.z.ai - The server 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 it with AES-256-CTR, and wraps the symmetric key - The archive is posted directly to Aliyun OSS, which calls back to Z.ai's backend to register the snapshot
During testing, the running client held persistent connections to zcode.z.ai and two Aliyun OSS nodes. Session logs showed 62 capture events from a single active session, triggered before every prompt and again on task completion.
No Toggle Stopped It
This is the detail that separates the incident from a mislabelled telemetry feature. ZCode's settings exposed two switches that sounded relevant:
| Setting | What it actually controlled |
|---|---|
| Optimize Experience | Only whether data was authorised for model training. Capture and upload continued. |
| Repo Snapshot Indexing | Only whether the server built a searchable index. Local packaging and upload continued. |
The capture component was instantiated unconditionally at startup, gated only on the token provider being able to produce a valid JWT. Critically, it ran as a host-level sidecar outside the agent tool loop — which is why no permission setting in the agent interface reached it.
For anyone building or evaluating agent tooling, that architecture is the lesson: a component outside the tool loop is outside every permission model you have.
ZCode's privacy policy states that it collects "text, files, and code submitted during conversations." Across the policy, FAQ, and changelog, there is no mention of packaging and uploading complete workspaces and full Git histories.
Why Git History Is Worse Than Source Code
If the archive had contained only working files, the exposure would be limited to the code you have open. A git object store is something else entirely:
- Deleted API keys survive. A secret removed in a later commit still exists in object history.
- Unpushed branch names leak intent. Naming conventions reveal unreleased products and internal projects.
.git/configcarries infrastructure detail — internal hostnames and repository paths.- It is years of engineering history, not a snapshot of the current tree.
That is why "rotate your credentials" is necessary but not sufficient. The correct response to a leaked object store is to assume anything ever committed is compromised, and to treat the history itself as sensitive.
What Z.ai Said
Z.ai responded through its official Feishu community:
- The issue has been fixed
- An apology to affected users
- A commitment to open-source ZCode's codebase so third parties can audit its security, with updates to follow
- Compensation: an extra weekly quota reset for all ZCode users
- A statement that uploaded data had been destroyed immediately
That last claim is the one to hold loosely. ferstar publicly questioned whether "immediate destruction" is verifiable from outside — and it is not. There is no independent audit, and no log a user can check.
The compensation also deserves scrutiny. A quota reset costs Z.ai nothing and addresses none of the actual risk. Users who ran the app on repositories containing credentials need key rotation and history review, not extra compute.
The Distinction People Missed
Part of why this spread — ferstar's post reached 276,000 views, and a Chinese-language alert thread drew another 63,800 — is a conflation worth naming precisely:
GLM the weights are open. ZCode the harness is closed.
These are different things. If you run GLM locally through Ollama or llama.cpp, ZCode is not involved. But if you installed ZCode to use those same GLM models with first-party integration, you were running a closed-source harness from the same company — and the open weights told you nothing about what that harness did.
The most-quoted reaction came from developer Petri Kuittinen: "My advice has been and continues to be: do NOT trust closed source AI harnesses." That is a strong position, and this incident is a concrete argument for it. A closed harness can add a host-level component that no visible setting governs, and you will only learn about it if someone reverses the binary.
Practically, it also means the models are separable from the incident: developers can continue using GLM open weights through other harnesses such as Codex, Claude Code, or local runtimes.
What to Do If You Used ZCode
- Treat every credential ever committed to an affected repository as compromised — including keys deleted in later commits. Rotate them.
- Review what was in your git history, not just your working tree: old
.envfiles, tokens in commit messages, unpushed branch names. - Check for the local artifacts — the encrypted archive and the log files on disk will tell you whether snapshots were being taken on your machine.
- Uninstall if you have not already, and verify no residual credentials remain in your global config.
- Watch the promised open-sourcing. Z.ai committed to publishing the codebase for third-party audit. Whether that happens, and what the audit finds, is the actual accountability test.
Summary
The ZCode incident is not a subtle privacy trade-off or a badly worded consent screen. It is a closed-source harness that packaged complete repository lineages, encrypted them with a key only the vendor could use, shipped them to third-party cloud storage by default, and offered no switch to stop it — while the privacy policy said nothing about it.
The mitigations Z.ai announced are reasonable as far as they go: a fix, an apology, a quota reset, and a promise to open-source the harness for audit. What remains unverifiable is the one thing users most need to know — where the data went and whether it still exists.
For developers, the takeaway is structural rather than company-specific: evaluate the harness, not just the model. Open weights tell you nothing about the client you install.
For the coding agents we do recommend, see Cursor Projects, Claude Code, and GitHub's own agent-driven rewrite; for the GLM models themselves, GLM-5.3.
Related Articles
Keep reading