ZCode âm thầm tải toàn bộ lịch sử Git của bạn lên đám mây
Ứng dụng lập trình AI ZCode của Zhipu bị phát hiện tự động đóng gói toàn bộ workspace — bao gồm cả lịch sử Git đầy đủ — rồi mã hóa và tải lên Aliyun OSS mà không có sự đồng ý rõ ràng của người dùng. Khóa giải mã chỉ nằm trên máy chủ, còn các tùy chọn trong giao diện không thể tắt được quá trình này.
ZCode âm thầm tải toàn bộ lịch sử Git của bạn lên đám mây
Một cuộc điều tra kỹ thuật đã phát hiện ZCode — ứng dụng lập trình AI chính thức của Zhipu — tự động đóng gói toàn bộ workspace của người dùng, bao gồm cả lịch sử Git đầy đủ, mã hóa rồi tải thẳng lên Aliyun OSS. Đáng chú ý, khóa giải mã chỉ tồn tại trên máy chủ, khiến cả người dùng lẫn chính ứng dụng đều không thể mở được tệp mã hóa nằm trên đĩa của mình.
Phát hiện từ một lần dọn dẹp dung lượng
Câu chuyện bắt đầu khá tình cờ: thư mục ~/.zcode chiếm tới hơn 700MB. Khi đào sâu vào cấu trúc thư mục, tác giả bài điều tra tìm thấy một tệp .enc nặng 313MB nằm trong v2/checkpoints/, kèm theo một tệp metadata mô tả trạng thái:
{
"workspacePath": "/Users/ferstar/myprojects/",
"lastCompressedSize": {
"encryptedSizeBytes": 313070842,
"workspaceSizeBytes": 345549173
},
"kind": "baseline",
"failureCount": 564
}
Diễn giải đơn giản: ứng dụng đã quét dự án thương mại đang hoạt động của người dùng, loại bỏ node_modules và một vài thư mục khác, rồi đóng gói phần còn lại (345MB) thành một tệp mã hóa 313MB với nhãn baseline — tức ảnh chụp toàn phần. Con số failureCount: 564 cho thấy đã có 564 lần tải lên thất bại, trong khi tệp vẫn nằm chờ trong thư mục pending/ để thử lại.
Điều đáng lo ngại là: kho mã nguồn của dự án này tổng cộng khoảng 10GB, nhưng sau khi trừ các thư viện phụ thuộc, phần 345MB còn lại gần như là toàn bộ tài sản trí tuệ cốt lõi.
Luồng tải lên được tái dựng từ mã nguồn
Nhật ký (log) không ghi rõ địa chỉ tải lên, nên tác giả đã giải nén app.asar của ứng dụng để phân tích. Quy trình được tái dựng lại như sau:
- Client gọi
zcode.z.aiđể xin thông tin xác thực, máy chủ trả vềsnapshot_id, khóa công khai RSA, giới hạn dung lượng, chữ ký biểu mẫu OSS và URL callback; - Client nén workspace thành
tar.gz, mã hóa bằng AES-256-CTR với khóa đối xứng tạm thời, rồi bọc khóa này bằng RSA-OAEP-SHA256; - Tệp
tar.gz.encđược POST thẳng lên Aliyun OSS, bỏ qua máy chủ ứng dụng của ZCode, sau đó OSS gọi callback về backend của Zhipu để đăng ký ảnh chụp.
Việc kiểm tra các kết nối đang hoạt động xác nhận điều này: tiến trình ZCode duy trì kết nối HTTPS liên tục tới các điểm cuối IP của zcode.z.ai cùng hai nút lưu trữ Aliyun OSS.
Điểm trớ trêu nhất: khóa thuộc về máy chủ
Quá trình mã hóa dùng kỹ thuật envelope encryption (mã hóa phong bì) chuẩn mực, nhưng có một chi tiết quyết định:
Khóa công khai RSA được máy chủ gửi xuống trong lúc thương lượng thông tin xác thực, còn khóa bí mật tương ứng không bao giờ xuất hiện trên máy người dùng.
Nói cách khác, tệp mã hóa 313MB nằm trên ổ đĩa của bạn không thể mở được bởi bạn, và cũng không thể mở được bởi chính client ZCode. Chỉ backend của Zhipu giữ chìa khóa.
Nếu tính năng này thực sự phục vụ việc khôi phục dữ liệu hay đồng bộ giữa các thiết bị cho người dùng, khóa giải mã phải nằm ở phía người dùng — giống như cách Git hay Time Machine hoạt động. Một khóa chỉ máy chủ dùng được phục vụ đúng một mục đích: đảm bảo máy chủ có thể đọc mã nguồn của bạn bất cứ lúc nào họ muốn.
Gần 90% nội dung bị đóng gói là .git
Dù bản mã hóa không thể đọc, bản kê tệp (manifest) sinh ra trong quá trình đóng gói vẫn được lưu cục bộ dưới dạng văn bản thuần. Phân tích một ảnh chụp gồm 42.411 tệp cho kết quả:
| Nội dung | Dung lượng | Tỷ lệ | Thông tin chứa |
|---|---|---|---|
.git/lfs/ | 196,1 MB | 56,8% | Bộ đệm LFS — toàn bộ tài nguyên nhị phân và media lớn từng tải về |
.git/objects/ | 102,2 MB | 29,6% | Kho đối tượng lịch sử commit đầy đủ |
.git/logs/ | 0,6 MB | 0,2% | Reflog — lịch sử nhánh cục bộ và dấu vết thao tác chưa đẩy lên |
| Mã nguồn & tài liệu | ~46,2 MB | 13,4% | src/, tệp cấu hình, tài liệu nội bộ |
Chỉ riêng thư mục .git đã chiếm 86,6% khối lượng dữ liệu tải lên.
Khi tải lên, đám mây nhận được nhiều hơn hẳn cây làm việc hiện tại — họ nhận được toàn bộ dòng lịch sử của kho mã kể từ ngày đầu tiên, bao gồm:
- Các khóa API và cấu hình nhạy cảm từng bị xóa trong những commit sau;
- Tên nhánh cục bộ chưa đẩy lên (tiết lộ kế hoạch tính năng chưa công bố);
- Tên máy chủ GitLab nội bộ và đường dẫn kho mã cấu hình trong
.git/config.
Ngoài ra, một manifest bổ sung tên repo_snapshot_extra_manifest còn băm các tệp cấu hình ZCode toàn cục (như settings.behavior.json) và gộp kèm theo mỗi lần chụp.
Sự thật về các nút bật/tắt trong giao diện
Phản ứng tự nhiên là vào phần cài đặt để tắt tính năng này. Nhưng khi đối chiếu các tùy chọn giao diện với mã nguồn, kết quả không mấy dễ chịu:
| Nút bật/tắt | Người dùng tưởng | Thực tế |
|---|---|---|
Tối ưu trải nghiệm (optimizeAgentExperienceEnabled) | Tắt thu thập dữ liệu / đo lường từ xa | Chỉ kiểm soát việc dữ liệu có được dùng để huấn luyện mô hình hay không. Việc chụp và tải lên vẫn chạy |
Lập chỉ mục ảnh chụp kho mã (repoSnapshotIndexingEnabled) | Tắt tính năng ảnh chụp | Chỉ kiểm soát việc máy chủ có lập chỉ mục ảnh chụp đã tải lên hay không. Việc đóng gói và tải lên cục bộ vẫn tiếp diễn |
Phân tích mã assembly cho thấy rõ: tiến trình phụ trách chụp và tải lên được khởi tạo vô điều kiện ngay khi ứng dụng khởi động. Không có bất kỳ kiểm tra điều kiện nào dựa trên tùy chọn người dùng; yêu cầu duy nhất là tokenProvider trả về được một JWT hợp lệ.
Kết luận: chỉ cần bạn đang đăng nhập, đường ống chạy nền này vẫn hoạt động thường trực, và không có tùy chọn giao diện nào tắt được nó.
Việc chụp được kích hoạt tại hai thời điểm: captureBeforePrompt (trước mỗi câu lệnh) và khi tác vụ hoàn tất có gắn nhãn repo-wiki-update. Trong nhật ký phiên làm việc, chỉ một phiên hoạt động đã sinh ra tới 62 sự kiện chụp.
Chính sách quyền riêng tư nói gì?
Chính sách quyền riêng tư của ZCode có nêu rõ việc thu thập "văn bản, tệp và mã nguồn được gửi trong các cuộc hội thoại" — đây là thông lệ phổ biến để cấp ngữ cảnh cho mô hình ngôn ngữ lớn.
Tuy nhiên, xuyên suốt toàn bộ chính sách, phần câu hỏi thường gặp và nhật ký thay đổi, không có một dòng nào đề cập tới việc âm thầm đóng gói và tải lên toàn bộ workspace cùng lịch sử Git đầy đủ. Câu gần nhất chỉ là mẫu câu chung chung: "chương trình tối ưu mặc định tắt, và dữ liệu đầu vào sẽ không được dùng để huấn luyện nếu không có sự đồng ý".
Cách phòng vệ: xóa tệp vô ích, phải khóa thư mục
Khi mới phát hiện gói dữ liệu đang chờ, tác giả đã xóa nó. Chưa đầy nửa giờ sau, ứng dụng chụp lại — một tệp 313MB mới toanh, bộ đếm thử lại nhảy từ 564 lên 565. Khi thấy tệp biến mất, trình tải lên chỉ việc đóng gói cái mới. Xóa thủ công chẳng khác nào chơi trò đập chuột chũi.
Giải pháp sạch sẽ và hiệu quả nhất là đặt cờ bất biến ở cấp hệ thống tệp, từ chối quyền ghi ngay tại tầng nhân hệ điều hành.
macOS
# Xóa và khóa thư mục checkpoints
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints
# Kiểm tra: phải báo "Operation not permitted"
touch ~/.zcode/v2/checkpoints/test
Linux
# Xóa và khóa thư mục checkpoints
rm -rf ~/.zcode/v2/checkpoints
mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints
# Kiểm tra: phải báo "Operation not permitted"
touch ~/.zcode/v2/checkpoints/test
Ảnh hưởng và cách hoàn tác
- Kết quả: logic chụp bị nhân hệ điều hành chặn mỗi khi cố ghi đĩa. Không có tệp cục bộ, đường ống tải lên không có gì để gửi;
- Đánh đổi: tính năng khôi phục ảnh chụp / dòng thời gian trong giao diện sẽ không hoạt động (vốn dĩ cũng chỉ hoạt động nhờ tải mã nguồn của bạn lên). Trò chuyện thông thường, gợi ý mã và thực thi công cụ vẫn chạy bình thường. Các lỗi vào/ra bị nuốt trong log là vô hại;
- Khôi phục: chạy
chflags nouchg ~/.zcode/v2/checkpoints(macOS) hoặcsudo chattr -i ~/.zcode/v2/checkpoints(Linux).
Góc nhìn cho người dùng Việt Nam
Với cộng đồng lập trình viên Việt Nam — những người ngày càng dùng nhiều công cụ lập trình AI trong các dự án outsource và sản phẩm thương mại — câu chuyện này đáng để lưu tâm ở hai điểm:
Thứ nhất, phạm vi dữ liệu. Suy luận mô hình cần ngữ cảnh mã liên quan tới tác vụ, điều này ai cũng chấp nhận. Nhưng chụp ảnh toàn bộ kho mã kèm lịch sử commit nhiều năm là chuyện hoàn toàn khác.
Thứ hai, tư thế kiến trúc. Nếu thực sự thiết kế cho việc khôi phục hoặc đồng bộ phía người dùng, khóa giải mã phải thuộc về người dùng. Một khóa mã hóa chỉ máy chủ giữ, không hề công bố trong chính sách quyền riêng tư, quá trình tải lên chạy nền không thể dừng, và việc đóng gói lại ngoan cố sau khi bị xóa — trông không giống sao lưu mà giống thu thập hơn.
Với các đội nhóm làm việc theo hợp đồng bảo mật (NDA) hoặc xử lý dữ liệu khách hàng, việc một công cụ tự động đẩy mã nguồn lên hạ tầng đám mây nước ngoài có thể là vi phạm thỏa thuận bảo mật và ảnh hưởng tới các yêu cầu tuân thủ. Kiểm tra kỹ thư mục ~/.zcode và áp dụng biện pháp khóa thư mục ở trên là bước nên làm ngay.
Công cụ vẫn là công cụ, nhưng người dùng phải tự vạch ra ranh giới của mình. Nếu phần mềm không cho bạn tắt, hãy dùng nhân hệ điều hành để nhốt nó vào lồng.

