Skip to content

ZCode âm thầm upload toàn bộ Git history lên cloud

Karify98 & Amy 🌸·
Cover Image for ZCode âm thầm upload toàn bộ Git history lên cloud

Một developer rảnh tay dọn ổ cứng phát hiện thư mục cấu hình của một AI coding app chiếm hơn 700MB. Đào sâu thêm, anh tìm ra thứ đáng lo hơn nhiều: toàn bộ Git history của dự án đang bị đóng gói, mã hóa và âm thầm gửi lên cloud — mà chính anh cũng không mở lại được.

Chuyện gì đang xảy ra

ZCode là AI coding desktop app chính thức của Zhipu — công ty Trung Quốc đứng sau dòng model GLM. Theo bài phân tích kỹ thuật của developer ferstar (blog.ferstar.org, đăng ngày 17/9/2026, lên top Hacker News với 231 điểm và gần 90 comment), chỉ cần đăng nhập ZCode, ứng dụng sẽ tự đóng gói toàn bộ workspace — bao gồm .git/objects, .git/lfs, reflog và config toàn cục — rồi upload thẳng lên Aliyun OSS.

Ferstar tìm thấy trong ~/.zcode/v2/checkpoints/ một file .enc nặng 313MB, kèm metadata ghi failureCount: 564 — tức app đã thử upload thất bại 564 lần và vẫn kiên trì retry. Repo gốc 10GB, sau khi loại node_modules còn lại 345MB gần như toàn bộ là mã nguồn và lịch sử commit.

Cơ chế: chìa khóa không nằm trong tay bạn

Đây là phần đáng chú ý nhất kỹ thuật. Luồng hoạt động ferstar dựng lại bằng cách giải ngược app.asar của ZCode:

  1. Client gọi zcode.z.ai xin credential upload
  2. Server trả về snapshot_id, form signature của Aliyun OSS, và một RSA public key sinh mới cho mỗi lần
  3. Client nén workspace, mã hóa bằng AES-256-CTR, rồi wrap symmetric key bằng RSA-OAEP-SHA256 với public key vừa nhận
  4. File .tar.gz.enc được POST thẳng lên Aliyun OSS, OSS gọi callback báo Zhipu backend đã nhận

Đây là envelope encryption giáo khoa — nhưng có một điểm khác biệt cố ý. Private key tương ứng với RSA public key đó chưa từng chạm vào máy người dùng. Nó chỉ tồn tại phía server Zhipu. Ferstar thử unwrap file bằng mọi private key cục bộ có sẵn — thất bại, như dự đoán.

Nói cách khác: file 313MB ciphertext nằm ngay trên ổ cứng của bạn, nhưng chỉ Zhipu mở được. Nếu tính năng này thật sự để rollback hay sync giữa các máy, key phải nằm ở phía người dùng — giống Git hay Time Machine vẫn làm. Key chỉ server giữ thì mục đích duy nhất hợp lý là để server đọc code bất cứ lúc nào muốn.

Toggle tắt trong UI không tắt được gì

Phản ứng tự nhiên là vào settings tắt tính năng. Ferstar đối chiếu hai công tắc với source code và thấy cả hai đều là bẫy:

Toggle Người dùng tưởng Thực tế
Optimize Experience Tắt thu thập dữ liệu Chỉ tắt việc dùng data để train model. Snapshot vẫn chạy
Repo Snapshot Indexing Tắt tính năng snapshot Chỉ tắt việc server index snapshot đã upload. Đóng gói và upload cục bộ vẫn tiếp tục

Nhìn vào code đã build, pipeline capture/upload được khởi tạo vô điều kiện ngay lúc app start — không có bất kỳ if-check nào theo user preference. Điều kiện duy nhất: token đăng nhập còn hợp lệ. Trigger xảy ra ở hai thời điểm — trước mỗi prompt và sau khi task hoàn thành — một session hoạt động có thể sinh tới 62 lần capture.

So what — ảnh hưởng gì tới developer?

Đây không phải chuyện "AI cần đọc code để trả lời câu hỏi" — điều mà hầu hết developer dùng AI coding tool đã chấp nhận từ đầu. Vấn đề nằm ở phạm vi dữ liệu và kiến trúc key.

Phạm vi: inference cần context liên quan tới task hiện tại. Snapshot ferstar mô tả lấy đi toàn bộ lịch sử Git — 86,6% payload chỉ riêng thư mục .git, gồm object store đầy đủ và reflog. Đó là API key cũ đã bị xóa ở commit sau, tên branch local chưa push tiết lộ roadmap tính năng chưa công bố, hostname nội bộ trong .git/config. Xóa một secret khỏi commit mới không có nghĩa nó biến mất khỏi Git history — và ZCode đang đóng gói đúng phần history đó gửi đi.

Kiến trúc key: một hệ thống backup hay sync hợp pháp thường để key ở phía người dùng. ZCode làm ngược lại — key chỉ tồn tại server-side, không disclosure rõ ràng trong privacy policy, không cách nào tắt qua UI, và tự động tái tạo file mới khi bị xóa thủ công (retry counter tăng từ 564 lên 565 chỉ sau nửa tiếng ferstar test). Ba đặc điểm này gộp lại giống thu thập dữ liệu có chủ đích hơn là tính năng phục vụ người dùng.

Với team đang cân nhắc AI coding tool cho môi trường có mã nguồn nhạy cảm, đây là lời nhắc kiểm tra kỹ hai điều trước khi cho phép cài: tool có tự đóng gói và upload workspace hay không, và nếu có, key giải mã nằm ở đâu. Câu trả lời "chúng tôi mã hóa dữ liệu của bạn" chỉ có ý nghĩa khi bạn — chứ không chỉ vendor — nắm được key.

Cách chặn (nếu vẫn cần dùng ZCode)

Ferstar thử xóa file pending — 30 phút sau app tạo lại bản mới, retry counter tiếp tục tăng. Xóa thủ công là whack-a-mole. Cách chặn hiệu quả là khóa write access ở tầng filesystem:

# macOS
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints

# Linux
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints

Kernel sẽ chặn mọi ghi đè vào thư mục này. Tính năng "checkpoint rollback" trong UI sẽ không hoạt động — nhưng tính năng đó vốn dĩ cũng cần upload code trước mới chạy được, nên mất nó không phải tổn thất lớn. Chat, autocomplete và các thao tác tool khác không bị ảnh hưởng.

Điều cần biết

  • ZCode (Zhipu) đóng gói toàn bộ .git history + config, mã hóa AES-256-CTR/RSA-OAEP, upload lên Aliyun OSS ngay khi đăng nhập
  • Private key giải mã chỉ tồn tại phía server — kể cả người dùng cũng không mở được file trên máy mình
  • Hai toggle trong settings không tắt được capture/upload, chỉ tắt training data hoặc server-side indexing
  • Trigger trước mỗi prompt và sau mỗi task — một session sinh tới 62 lần capture
  • Chặn bằng cách khóa filesystem write vào ~/.zcode/v2/checkpoints (chưa có fix chính thức từ Zhipu tại thời điểm bài viết)

Đây là phát hiện độc lập từ một developer, chưa có phản hồi chính thức từ Zhipu tại thời điểm viết bài. Nhưng riêng việc kiến trúc key được thiết kế sao cho chỉ server mở được — trong khi privacy policy không nhắc tới hành vi này — đã đủ để bất kỳ ai cài ZCode trên máy có mã nguồn thương mại nên dừng lại kiểm tra ngay, thay vì đợi Zhipu lên tiếng.


Bài viết được hỗ trợ bởi AI (Amy 🌸). Nội dung đã được kiểm duyệt bởi tác giả.

Related Posts