A coding agent's login screen is an authorization boundary, but it is not a data-flow map. Before giving a desktop agent access to a real repository, freeze the client version, open a canary repository, and compare filesystem and network behavior across logged-out, logged-in idle, prompt, and exit states. The ZCode incident shows why this needs to happen before trust is granted, not after a privacy dispute.
Reading time: 10 minutes · About 2,000 words
TL;DR
- ZCode's official changelog says version 3.14.0 fixed abnormal uploads in Repo Wiki. Its later public statement says the snapshot-generation and upload path was removed.
- Independent forensics on version 3.12.3 found a full-workspace packaging path that included
.git. The reported 313 MB commercial archive failed to upload; a separate 538-file public repository snapshot was reported as accepted by the service. - Encryption does not establish privacy by itself. The useful questions are what was packed, when transmission started, which party held the decryption key, and how deletion can be verified.
- Current open source code is evidence about the remediated state. It does not reconstruct the removed implementation or the complete lifecycle of previously uploaded data.
- A practical pre-login audit freezes the artifact, uses canary files, captures filesystem and egress behavior by authentication state, tests every control, and records retention and deletion evidence.
What the ZCode evidence actually supports
Three evidence layers need to stay separate.
First, ZCode's official changelog says version 3.14.0 fixed abnormal uploads in Repo Wiki. In a September 21 public statement, ZCode apologized, said that no affected code data was retained or used for model training, and summarized assessments by CAICT and NSFOCUS. According to that statement, the relevant object-storage bucket was empty or deleted and version 3.14.0 removed Repo Wiki, local repository snapshot generation, and the upload workflow. The complete assessment reports were not linked publicly at the time of this review, so these are vendor-published summaries of third-party findings rather than independently reviewed reports.
Second, an independent forensic investigation by ferstar examined ZCode 3.12.3. It reported a local manifest containing 42,411 files and an encrypted 313 MB archive built from a 345 MB commercial workspace. About 86.6% of that manifest's bytes came from .git, including objects, LFS content, and reflogs. The reconstructed path requested upload credentials, encrypted an archive with AES-256-CTR, wrapped its key with a server-provided RSA public key, and targeted Alibaba Cloud OSS.
One correction is essential: that large commercial archive remained pending after 564 failed attempts and did not leave the researcher's network. A separate small public repository, containing 538 files and producing an archive of roughly 15 KB, had a service-accepted status. This supports the existence of a functioning upload path in at least one observed case. It does not support the broader claim that every 42,411-file archive, every repository, or every user's code was successfully uploaded.
Third, the current ZCode repository exposes the remediated implementation. The public tree for v3.14.3 contains a detailed NOTICE describing many data and execution paths. Its current checkpoint implementation uses local Git operations and local metadata. Searches of this tree do not recover the reported legacy snapshot credential endpoint or encryption pipeline. That is useful evidence that the current design differs. Because the affected 3.12.3 source and the deletion diff are absent, the current tree cannot independently prove every detail of the previous implementation or historical server-side handling.
The strongest conclusion is therefore narrower than a headline about theft: an official fix and apology confirm a repository-upload problem, independent forensics documents the old client path and at least one accepted test repository, and the public evidence does not let an outsider replay the full pre-fix data lifecycle.
Why ordinary privacy checks miss the problem
Teams usually ask whether prompts train a model, whether telemetry can be disabled, and whether transport uses encryption. Those checks cover only part of the system.
A coding agent can have several independent outbound paths:
| Path | Typical trigger | Possible payload | Control to verify |
|---|---|---|---|
| Model inference | User sends a prompt | selected files, diffs, tool output | context preview and provider policy |
| Product telemetry | launch, crash, feature use | events, device and session identifiers | telemetry control and schema |
| Repository indexing | workspace open, login, prompt, refresh | paths, symbols, source, archive or index | explicit scope and egress trace |
| Feedback and diagnostics | user submits a report | logs, screenshots, attachments | preview, redaction and consent |
| Sync or remote execution | account or workspace connection | sessions, configuration, credentials, files | target identity and retention |
Turning off model training does not necessarily disable indexing. Turning off telemetry does not necessarily stop a separate host-side service. Encrypting an archive protects it in transit or at rest from some observers, but says nothing about the party holding the private key.
This is also why static data-flow scanners solve a different problem. Tools such as HoundDog trace sensitive values through the application being developed. They can answer where an application's PII reaches a log, database, API, or model. A coding-agent audit asks an earlier question: what does the development tool itself read and transmit when it opens that repository?
The pre-login audit contract
Treat every claim as a small testable record rather than one global safe or unsafe verdict.
claim: logged_out_idle_has_no_repository_egress
artifact: installer hash + version + operating system
input: canary repository hash
state: logged out, five minutes idle
evidence: filesystem trace + DNS/connection log + byte counts
pass: no canary marker or repository archive reaches a remote sink
unknown: encrypted traffic exists but process attribution is incomplete
fail: attributed repository payload or staging archive appears
The contract should record seven fields for every observed flow: actor, source, transformation, trigger, authentication state, sink, and retention. Add the client hash, configuration, time window, reviewer, and raw evidence location so another person can repeat the test.
1. Freeze the artifact and environment
Record the installer hash, displayed version, update channel, operating system, account state, and every relevant preference. Disable automatic updates for the isolated test. A result from 3.12.3 cannot be silently generalized to 3.14.0, and a test that updates midway cannot be reproduced.
Use a disposable operating-system account or virtual machine with no production credentials. Start with a deny-by-default network policy and allow destinations deliberately as the test progresses.
2. Build a canary repository
Never begin with commercial source. Create a small repository containing unique, harmless markers in different locations:
- one tracked source file;
- one ignored file;
- one untracked file;
- one value committed and later deleted so it remains only in Git history;
- one LFS object if the tool claims LFS support;
- one dummy hostname and one fake API-key pattern;
- one symlink that points outside the repository.
Hash the repository and list its files before each run. Markers let you distinguish generic TLS traffic from content originating in the test repository.
3. Run an authentication-state differential
Repeat the same observation window across these states:
- first launch before login;
- login screen idle;
- logged in with no workspace;
- canary workspace open but idle;
- one prompt that does not request repository context;
- one prompt that explicitly references one file;
- app closed, signed out, and uninstalled.
For every state, capture new and modified files, process trees, DNS lookups, remote endpoints, connection byte counts, and application logs. On macOS, fs_usage, lsof, and a firewall such as Little Snitch can establish process attribution. Linux equivalents include inotifywait, strace, lsof, and OpenSnitch. A TLS-intercepting proxy can reveal payloads only when certificate trust and pinning permit it; endpoint and volume evidence remain useful when content is opaque.
4. Inspect staging artifacts before egress
Local evidence often answers what encrypted network capture cannot. Watch application data directories for manifests, archives, queues, retry counters, and credential responses. Compare staged file lists with the canary inventory. Check whether .git, ignored files, deleted history, external symlink targets, global configuration, and credentials are included.
Do not equate archive creation with successful upload. Keep separate states for created, queued, attempted, bytes sent, server accepted, indexed, and deleted. The distinction between the failed 313 MB archive and the accepted small repository in the ZCode report is exactly why this state model matters.
5. Test each control against behavior
Toggle telemetry, model-training, repository indexing, remote sync, crash reporting, and diagnostics one at a time. Repeat the same frozen test and compare evidence. A control passes only when its documented scope matches the actual changed flow.
Also test sign-out and revocation. Does sign-out stop retry queues? Does disabling indexing delete local staging data? Can the user identify and delete server-side objects? Is there a deletion receipt or only a UI success message?
6. Verify remediation and deletion separately
A new version with the upload code removed proves a current capability change. It does not prove that old objects, replicas, logs, derived indexes, or backups are gone. Remediation needs two ledgers:
- client ledger: version, code or binary evidence, removed trigger, regression test;
- data ledger: affected object classes, storage locations, deletion actor, time, independent check, backup and derived-data treatment.
Vendor attestation, a zero-object listing, and an independent lifecycle audit have different strengths. Publish which one was obtained.
A release gate for real repositories
Promote a coding agent from canary to real source only when all of these conditions are met:
- the tested artifact and configuration are pinned;
- observed outbound destinations match a documented allowlist;
- file and Git-history scope matches the feature being used;
- every preference has behaviorally verified semantics;
- encrypted storage identifies who can decrypt it;
- retry, logout, retention, and deletion behavior are documented and tested;
- regression monitoring alerts when version, endpoint, byte volume, or file scope changes.
This boundary complements two controls already covered here. The pre-install trust boundary decides which dependency may execute. The backup and restore contract preserves recovery after an allowed tool makes a destructive change. The data-flow audit decides which repository material an allowed tool may read and send.
FAQ
Does using a local model keep repository data local?
Only if the entire harness is local. A desktop client can run a local model while separately contacting telemetry, indexing, account, update, feedback, or sync services. Audit the process and its destinations, not the model label.
Is disabling telemetry enough?
No. Telemetry, model inference, indexing, diagnostics, and sync can be separate pipelines with separate controls. Test each control against filesystem and network behavior.
Does encryption prove that the vendor cannot read an upload?
No. Determine who controls the decryption key. Server-held private keys protect an archive from unrelated observers while still allowing the service to decrypt it.
Does an open source current version prove what an older binary did?
It proves what can be inspected in the published state. Historical claims require the affected source, reproducible binaries, network evidence, or other artifacts from that version.
What is the minimum useful audit?
Use a disposable account and canary repository, freeze the client hash, compare logged-out and logged-in idle states, record changed files and remote endpoints, and verify that logout stops pending work. This small test will not prove universal safety, but it catches hidden staging and unconditional background flows before real source is exposed.
Make login an evidence gate
Choose one coding agent and run the seven-state canary test before its next upgrade. Save the artifact hash, repository manifest, filesystem diff, endpoint list, and decision. The goal is not to prove a tool safe forever. It is to make every new version earn access to real repositories with evidence that can be replayed.