AI-LECTURER 速報課|2026-09-19|約 25 分鐘

你打不開的加密檔:AI 寫程式軟體把整個專案和 Git 歷史送上雲端

取材:Inside ZCode: Silently uploading your Git history to the cloud(Hacker News(AI 高人氣))
📍 真實場景
林怡君,32 歲,接案的後端工程師,手上有一份簽了保密合約(NDA)的電商客戶專案

她剛裝好一套 AI 寫程式的桌面軟體來幫客戶專案重構程式,順手整理硬碟時,發現家目錄裡有個隱藏資料夾佔了 700MB 以上。

😖 卡住的地方:她看不懂裡面的檔案,也不確定這些東西是不是客戶原始碼的副本,更不知道有沒有被傳出去。合約寫著原始碼不得外流,她卻連該從哪裡查起都不知道。
💡 這課帶你拆解 ZCode 事件的完整技術證據鏈:軟體怎麼把整個專案打包加密、送到哪裡、為什麼連你自己都打不開。你還會在瀏覽器裡親手做一次同樣的加密流程,之後看任何 AI 工具都能問出對的問題。

🧭 這到底是什麼(白話版)

ZCode 是智譜推出的 AI 寫程式桌面軟體安裝在你電腦上、有自己視窗的程式,不是打開網頁使用的服務。一位開發者(部落格作者 ferstar)整理硬碟時,發現家目錄下的隱藏資料夾 ~/.zcode 佔了 700MB 以上,於是一路追查。他的結論是:只要你登入,這個軟體會在背景把整個工作區打包、加密,再上傳到阿里雲的雲端儲存。打包內容包含完整的 Git 修改歷史。

被打包的東西不只是你看得到的程式檔。Git 歷史Git 是幫程式碼記錄每一次修改的工具,歷史就是所有舊版本與修改紀錄的完整日記存放在專案裡的 .git 隱藏資料夾。文章說,LFS 大檔案快取(LFSGit 用來管理圖片、模型這類大檔案的擴充功能)、reflog(reflogGit 偷偷記下你每次切換分支、改寫歷史的操作流水帳)和軟體的全域設定,也都在包裡。文章的實例是一個總共約 10GB 的商業專案:扣掉 node_modules 等相依套件後,剩下 345MB 被壓成 313MB 的加密檔。作者形容這幾乎全是核心智慧財產。

諷刺的是加密的方式。伺服器每次臨時發一把 RSA 公鑰一把只能「上鎖」、不能「開鎖」的鑰匙,可以公開發給任何人;對應的開鎖鑰匙叫私鑰給你的電腦,電腦用它把資料的加密金鑰鎖起來,而私鑰只存在雲端。結果是:幾百 MB 的密文明明躺在你自己的硬碟裡,你打不開,連 ZCode 用戶端本身也打不開。

先劃一條誠實的界線:這是單一作者靠逆向把成品軟體拆開,倒推它內部怎麼運作的做法軟體的 app.asar桌面軟體把自己的程式碼打包成的一個檔案,拆開就能讀到裡面的邏輯得出的調查,作者也說明文章是 AI 翻譯的。我們手上沒有廠商的回應。另外,作者硬碟上那個 313MB 檔案其實是「上傳失敗 564 次、卡在待上傳」的狀態。所以這課的目標不是下結論罵誰,而是學會拆解這類事件的證據,再決定怎麼保護自己的專案。

🎯 為什麼值得你花時間

已刪掉的秘密,還活在 Git 歷史裡你以為早就刪掉的資料庫密碼、API 金鑰,只要曾經被 commit 過,就還躺在 .git 的舊紀錄裡。當工具打包的是「完整 .git 歷史」而不只是最新檔案,外流的範圍就從「現在的程式碼」擴大到「這個專案有史以來的所有內容」。
加密不等於你能看見、能稽核檔案有加密聽起來很安心,但這個案例裡,你連自己硬碟上的密文都打不開,無法確認裡面裝了什麼,也無法證明它沒裝什麼。私鑰握在誰手裡,才決定資料真正屬於誰。
AI 工具天生需要讀你的整個專案AI 寫程式工具要能幫忙,就得讀取你的工作區,這本身合理。問題出在「讀取」之後的去向。對接案者來說,商業專案背後往往是保密合約,一次不知情的上傳就可能造成違約風險。使用者必須主動檢查,因為工具不會替你提醒。

⚙️ 它是怎麼運作的

1
登入後,背景掃描你的工作區只要你登入 ZCode,它會掃描你正在使用的專案,排除 node_modules 等少數目錄,把剩下的內容(包含 .git、LFS 快取、reflog)列入打包範圍。
2
向伺服器索取上傳憑證用戶端對 zcode.z.ai 送出 POST /api/v1/snapshot/upload-credential。伺服器回傳一包東西:快照編號 snapshot_id、這一輪專用的 RSA 公鑰、大小上限 max_size、阿里雲 OSS 的表單簽章(policy、x-oss-signature),還有回呼設定 callback。
3
本機打包並加密先把檔案壓成 tar.gz,再用 AES-256-CTR一種速度很快的加密方法,用同一把金鑰上鎖與開鎖,適合處理大檔案加密整包內容,最後用 RSA-OAEP 這種公鑰加密用公開的鑰匙上鎖,只有持有對應私鑰的人才能開鎖的加密方式把 AES 金鑰包起來。這種「大檔用 AES、金鑰用 RSA 包」的做法叫混合加密。
4
直傳阿里雲 OSS加密完成的 tar.gz.enc 不經過 ZCode 伺服器,而是用剛拿到的簽章,以 PostObject 表單方式直接上傳到阿里雲的物件儲存(OSS)雲端的大型檔案倉庫,你把整個檔案丟進去,它幫你存放並給一個網址編號
5
回呼確認,失敗就留著重試上傳成功後,OSS 透過 callback 通知 ZCode 伺服器收到了。失敗的話,檔案留在本機 pending/ 目錄等下次重試。作者看到的那個 313MB 檔案,狀態檔記錄了 failureCount 為 564。
同樣叫「加密上傳」,誰握有私鑰差很多(左欄為一般自己保管金鑰的做法,僅供對照)
比較項目自己保管金鑰的加密備份(對照組)文章描述的 ZCode 做法
公鑰由誰產生你自己在本機產生伺服器每次臨時發放,隨 snapshot_id 一起回傳
私鑰放在哪你自己保管只存在雲端
你能解開自己硬碟上的密文嗎不能
用戶端軟體本身能解開嗎不能(作者的說法)
誰決定內容能不能被讀取持有私鑰的一方

🔍 程式碼漫遊(點有 ● 的行看白話講解)

這是作者在 ~/.zcode/v2/checkpoints/ 裡,那個 313MB .enc 檔旁邊找到的狀態紀錄。從這 9 行就能讀出軟體到底在做什麼。

{
💬 這是一份 JSON 格式的狀態檔。JSON 是一種用大括號與「名稱: 值」記錄資料的文字格式,這類描述資料的資料也叫 metadata。
"workspacePath": "/Users/ferstar/myprojects/<a commercial project>",
💬 被打包的專案路徑。作者說這是他正在開發的商業專案,也就是軟體掃描的是你「正在用」的專案,而不是隨便一個資料夾。
"lastCompressedSize": {
💬 「最近一次壓縮後的大小」紀錄,底下兩行是打包前後的對照。
"encryptedSizeBytes": 313070842,
💬 加密後約 313MB,就是硬碟上那個 .enc 檔的大小。
"workspaceSizeBytes": 345549173
💬 打包前的工作區約 345MB,是已經排除 node_modules 等目錄之後的大小。加密檔約為它的 91%,這個比例是我們用兩個數字算出來的。
},
💬 大小紀錄結束。
"kind": "baseline",
💬 重點行:作者解讀為「完整快照」,也就是整個專案的全量備份,而不是只記變動的部分。
"failureCount": 564
💬 重點行:上傳嘗試失敗了 564 次,檔案因此卡在本機待重試。這代表任務會反覆嘗試,但不能單憑這一行就說這份檔案已經送出。
}
💬 狀態檔結束。

🛠️ 動手做:信封實驗:你拿著密文,卻打不開

  1. 依序按 ① 到 ④,每按一次就看下方黑底紀錄多了什麼。按鈕會依步驟逐一解鎖。
  2. 按 ① 時想想:這一步對應文章裡哪個動作?答案是 POST /api/v1/snapshot/upload-credential,也就是伺服器發放公鑰。
  3. 按 ② 之前,可以先把文字框改成你想像中的機密內容,例如客戶專案的 commit 紀錄。觀察加密後只剩一串看不懂的十六進位碼。
  4. 按 ③ 時注意:出現錯誤不是程式壞了,而是設計如此。公鑰只能上鎖,不能開鎖,而且 AES 金鑰在包好信封後就被丟棄了。
  5. 按 ④ 時觀察:只有拿著私鑰的一方才能取回原文。文章裡的處境,就是你只能按到 ③,永遠沒有 ④。
  6. 想一想:如果你是客戶,你能不能證明這包密文裡沒有你的原始碼?
  7. 注意:這是用瀏覽器內建的 WebCrypto 重現同類演算法(AES-CTR + RSA-OAEP)的教學模擬,不是 ZCode 的真實程式碼。
👇 下面是活的,直接操作

🧠 工程思維透鏡(資深工程師看到的是什麼)

🔭 把私鑰只放在雲端,工程上有什麼好處?代價是什麼?
可能的設計理由(文章並沒有證實廠商的動機):伺服器每輪動態發公鑰,可以集中換鑰與控管;即使有人偷到你硬碟上的密文,沒有私鑰也讀不出內容。代價是使用者失去驗證權與資料主權,資料的可讀性完全取決於雲端。更值得追問的是:如果這個功能的目的是讓你「還原檢查點」,連用戶端本身都解不開密文,代表還原必須先經過雲端。這件事能不能解釋得通,資深工程師會直接向廠商要答案。
🔭 為什麼「預設值」比「說明文件」更重要?
作者是整理硬碟時偶然發現的,代表登入後自動上傳,沒有明確的提示或同意流程(文章標題用 silently)。工程上這是 opt-out(預設開啟、要自己關)與 opt-in(預設關閉、同意才開)的差別。資深工程師評估任何會傳出資料的功能,會問四件事:使用者知情嗎?同意過嗎?能關嗎?關掉後核心功能還能用嗎?文章結尾提供了關閉方法,但那段不在本課取得的摘錄內,所以本課不猜測細節。
🔭 「排除 node_modules 等少數目錄」這種黑名單設計,風險在哪?
黑名單是預設全收、只挑已知不要的排除;白名單則是預設不收、明確列入才收。黑名單的風險在於,只要有人沒想到的檔案,例如 .env 之類的秘密檔案,就會被一併收走。本課取得的摘錄只提到排除 node_modules 等少數目錄,沒有提到秘密檔案是否被排除,所以這是該去驗證的問題,不是結論。資料最小化原則正是為了避免這種情況:能不收就不收。
🔭 一個失敗 564 次的背景任務,說明了什麼工程問題?
564 次失敗代表這個任務沒有向使用者浮出錯誤,也看不出明顯的重試上限,硬碟上的 .enc 檔就這樣默默累積。好的背景任務應該有重試上限與退避(失敗後間隔越拉越長)、使用者看得到的狀態、以及一鍵關閉。作者是因為清硬碟才發現,等於是可觀測性缺席、靠運氣才被看見。

📝 隨堂考(點選答案,立即回饋)

Q1. 依文章的說法,為什麼連 ZCode 用戶端自己也解不開那個 .enc 檔?
✅ 混合加密中,AES 金鑰被 RSA 公鑰上鎖,只有私鑰能開。文章指出私鑰只在雲端,所以硬碟上的密文,你和用戶端都無法解開。
Q2. 狀態檔裡 failureCount 是 564,最合理的解讀是什麼?
✅ 文章記錄的是 564 次失敗,檔案因此留在本機。這也提醒我們要區分證據:這一份檔案沒送出去,但整個機制顯示登入後會持續嘗試上傳。
Q3. 你三個月前不小心把資料庫密碼 commit 進專案,隔天就刪掉了。如果工作區連同完整 .git 歷史被打包,會怎樣?
✅ Git 會保留每一次修改。刪掉最新檔案裡的密碼,舊 commit 裡仍然有,所以打包完整 .git 會把已刪的秘密一併帶走。
Q4. 為什麼流程要用 AES 加密大檔案,再用 RSA 只包那把 AES 金鑰?
✅ 這是混合加密的標準分工:AES 負責又快又大量的加密,RSA 負責安全地交付那把很小的金鑰。文章描述的流程就是 AES-256-CTR 加密加上 RSA-OAEP 包金鑰。
Q5. 以下哪個結論,從這篇文章的技術證據中「最不足以」直接得出?
✅ 技術證據能說明「發生了什麼」,例如檔案、API 路徑和金鑰流程,但無法證明「為什麼這樣做」。廠商的動機需要廠商本身的說明,這是分辨事實與推論的關鍵。

🃏 翻牌記憶卡(先想答案,再點開對答)

「加密上傳」為什麼不等於「隱私安全」?點我翻面
關鍵在誰握有私鑰。如果私鑰只在雲端,你的資料對你不透明、你無法稽核內容,能否被讀取完全由持有私鑰的一方決定。
混合加密的三步驟?點我翻面
①隨機 AES 金鑰加密資料;②用 RSA 公鑰把 AES 金鑰包起來;③把密文和上鎖的金鑰一起送出。
為什麼 .git 資料夾是高風險?點我翻面
它含完整修改歷史,已刪掉的密碼、金鑰和舊版程式碼都還在,被整包帶走時範圍遠大於「現在的檔案」。
failureCount 564 說明了什麼?點我翻面
該次快照上傳失敗 564 次,卡在本機 pending/ 等重試。不能推論它已送出,但顯示背景任務會持續重試。
文章裡伺服器在上傳流程中扮演什麼角色?點我翻面
發放憑證:快照編號、RSA 公鑰、大小上限、OSS 表單簽章與 callback。檔案由用戶端直傳阿里雲 OSS,OSS 再用 callback 通知伺服器收到。
最快的自查起手式是什麼?點我翻面
看 AI 工具在家目錄的隱藏資料夾有多大、裡面有什麼,特別留意 checkpoints、pending 這類位置與不明的大型 .enc 檔。本案就是先發現 ~/.zcode 佔 700MB 以上才追查出來的。

✅ 離開前自測(全勾=這課真的學會了)

0%