CL-SN55 941 —
GPT-61S 885 —
GPT-56T 861 —
GPT-6S 825 —
CL-OP55X 819 —
MUSE-SPK 793 —
QWEN-38X 779 —
GPT-6A 778 —
CL-OP5H 712 —
CL-OP5X 710 —
KIMI-K3X 700 —
CL-OP46H 695 —
CL-FAB5H 693 —
CL-OP55H 693 —
CL-OP47H 684 —
GEM-37FH 649 —
GEM-38FH 634 —
GPT-56S 561 -0.4%
INKL 531 —
CL-OP47 530 -0.4%
GEM-3P 493 —
CL-OP46 488 -0.2%
CL-OP48 481 —
GEM-31P 454 -0.2%
GPT-6L 436 —
CL-SN55 941 —
GPT-61S 885 —
GPT-56T 861 —
GPT-6S 825 —
CL-OP55X 819 —
MUSE-SPK 793 —
QWEN-38X 779 —
GPT-6A 778 —
CL-OP5H 712 —
CL-OP5X 710 —
KIMI-K3X 700 —
CL-OP46H 695 —
CL-FAB5H 693 —
CL-OP55H 693 —
CL-OP47H 684 —
GEM-37FH 649 —
GEM-38FH 634 —
GPT-56S 561 -0.4%
INKL 531 —
CL-OP47 530 -0.4%
GEM-3P 493 —
CL-OP46 488 -0.2%
CL-OP48 481 —
GEM-31P 454 -0.2%
GPT-6L 436 —
← Back to feed

ZCode Silently Packages Entire Git Histories and Uploads Them to Alibaba Cloud — No UI Toggle Stops It

On September 17, 2026, developer ferstar published a reverse-engineering walkthrough of ZCode, Z.ai’s official AI coding desktop app built on GLM open-weight models. The finding: whenever the app is logged in, ZCode silently packages the user’s entire workspace — including the complete .git history, LFS asset cache, reflogs, and global app configs — encrypts it, and uploads the archive directly to Alibaba Cloud object storage (Aliyun OSS).

The archive ferstar found on their own machine: 313MB encrypted package from a 345MB commercial workspace, 42,411 files, 564 failed upload attempts still waiting to retry. The .git directory alone accounted for 86.6% of the payload.

The Key Is Only On Z.ai’s Servers

ZCode uses envelope encryption. The payload is encrypted with AES-256-CTR, and the symmetric key is wrapped using an RSA-OAEP public key delivered by Z.ai’s server at upload time. The corresponding private key never touches the user’s machine.

The 313MB ciphertext sitting on the user’s own disk cannot be decrypted by the user. The ZCode client cannot decrypt it either. Only Z.ai’s backend holds the key.

Upload flow, reconstructed from the client’s app.asar:

  1. ZCode requests credentials from zcode.z.ai, which returns OSS form signatures, a snapshot ID, a per-round RSA public key, and an Aliyun OSS endpoint.
  2. The client packs the workspace to tar.gz, encrypts with AES-256-CTR, wraps the symmetric key with the server-provided RSA public key.
  3. The archive posts directly to Aliyun OSS, which callbacks to Z.ai’s backend to register the snapshot.

A single session generated up to 62 capture events — triggered before every prompt and on task completion.

No Toggle Stops It

ZCode’s settings expose two relevant switches:

  • Optimize Experience (optimizeAgentExperienceEnabled): controls only whether data is used for model training. Snapshot capture and upload continue regardless.
  • Repo Snapshot Indexing (repoSnapshotIndexingEnabled): controls only whether the server builds a searchable index. Local packaging and upload continue regardless.

The host assembly code instantiates the capture sidecar unconditionally at startup. The only requirement is a valid JWT from the token provider. The pipeline is not an agent tool — it runs as a host-level sidecar outside the agent tool loop, which is why no permission setting in the agent interface reaches it.

ZCode’s privacy policy states it collects “text, files, and code submitted during conversations.” Across the entire policy, FAQ, and changelog, there is no mention of packaging and uploading complete workspaces and full Git histories.

What a Git Object Store Contains

A Git object store is not a snapshot of the working tree — it is the complete lineage of the repository since the first commit. Deleted API keys from old commits survive in object history. Unpushed branch names that reveal unreleased product plans are in there. Internal hostnames and repository paths from .git/config are in there. An uploaded archive is years of engineering history, not just currently open files.

Independent Windows testing confirmed identical behavior. One researcher found 32 workspaces with snapshots taken; 14 showed no failure records, indicating successful uploads. The largest package was 107MB. A secondary finding: ZCode’s global model-providers.json and provider_config.json — which store API keys in plaintext — are included in the uploaded manifest across every workspace.

The Confirmation

When ferstar’s post circulated on X, the most prominent reply came from an account affiliated with the ZCode team: “hey I am sorry to let you find it.” The official Z.ai account had not responded as of publication. The post passed 276,000 views within 13 hours.

ZCode launched in July 2026. Its pitch ran on trust — Z.ai positioned the harness against Claude Code weeks after Claude Code’s hidden-telemetry controversy, with open weights cited as the alternative to vendor control. A Z.ai executive, asked directly whether ZCode would include “any sort of spyware,” replied the company would not implement “anything beyond what’s listed” on the ZCode website.

The Fix

Blocking the checkpoint directory at the kernel level stops uploads while leaving chat, autocomplete, and tool calls functional:

macOS/Linux:

sudo chattr +i ~/.zcode/v2/checkpoints

Windows (PowerShell):

icacls "$env:USERPROFILE\.zcode\v2\checkpoints" /inheritance:r /grant "${env:USERNAME}:(OI)(CI)(RX)" /deny "${env:USERNAME}:(OI)(CI)(WD,AD,WEA,WA)"

The checkpoint rollback UI stops working. That feature required uploading your code in the first place.

The Model Layer Is Not the Trust Surface

Running open-weight GLM models locally is real: no per-token bill, no vendor lock-in. The ZCode case sharpens the boundary past the model. A locally-running open-weight model inside a cloud-phoning harness is not a local deployment. The trust surface includes the runtime, the desktop app, and the update pipeline — not just the weights.