先問你一個平常不會想的問題:clone 一個 repo、用 Cursor 打開它——這個動作本身安全嗎?

我一直以為是安全的。打開專案又不是執行程式,頂多 Cursor 幫我讀一讀檔案、跑跑 language server、在狀態列顯示現在是哪個 branch。這些都是唯讀的操作,能出什麼事。

7 月 14 號 Mindgard 公開的一個 0day 把這個假設打碎了。他們證明:只要在 repo 根目錄放一個叫 git.exe 的檔案,Windows 使用者用 Cursor 打開這個專案的當下,那個 git.exe 就會被執行——沒有提示、沒有確認、沒有任何一步需要你點「同意」。你以為你只是打開了一個資料夾,實際上你剛剛在自己的帳號權限下跑了一支來路不明的執行檔。

這篇要拆的就是這條攻擊鏈。它的每一步單獨看都無聊到不行,但串起來就是一次任意程式碼執行。更難看的是後半段:Mindgard 從去年 12 月就通報了,中間經過大半年、無數次版本更新,到公開這天都還沒等到修補完成的通知。

攻擊拆給你看

Mindgard 的 PoC 沒有用什麼花俏的 payload,就是把 Windows 內建的小算盤 calc.exe 複製一份、改名成 git.exe,丟進一個乾淨 repo 的根目錄,然後用 Cursor 打開這個資料夾。

小算盤跳出來了,而且不只跳一次。Cursor 在正常運作過程中會反覆呼叫 git,每呼叫一次就多執行一次那個假的 git.exe,於是小算盤一個接一個彈出來,很快淹沒整個畫面。

小算盤當然是無害的,它只是把「這個檔案真的被執行了」這件事變得肉眼可見。真實攻擊者塞進去的不會是 calc.exe,而是一個會在背景拉第二階段 payload、開反向 shell、或直接抓走你 SSH key 和雲端憑證的東西。差別只在那個 git.exe 裡面寫了什麼,觸發的機制一模一樣。

把攻擊者這一側的 repo 攤開來看,就是這麼平淡:

1
2
3
4
5
6
totally-normal-project/
├── README.md # 看起來人畜無害
├── package.json
├── src/
│ └── index.js # 程式碼經得起 review
└── git.exe # ← 唯一的惡意成分,一個偽裝成 git 的執行檔

沒有可疑的 npm script、沒有混淆過的程式碼、沒有藏在 postinstall 裡的指令。一個只盯著 package script 或 git hook 看的檢查流程,很可能整個漏掉它。唯一的異常是根目錄多了一個 git.exe,而大部分人 clone 完根本不會去數根目錄有幾個檔案,更不會覺得一個叫 git 的東西有問題——它看起來就該在那。

根因:workspace 不該出現在執行檔的搜尋路徑裡

問題出在 Cursor 怎麼找 git 這支程式。

Cursor 是 VS Code 的 fork,沿用了它的 Git 整合。當你打開一個資料夾,編輯器需要一支 git 執行檔來做版本控制。Mindgard 證實的核心事實是:這個尋找 git 的過程,最後選中了 workspace 根目錄裡那支惡意的 git.exe。repo 裡的一個檔案,就這樣從「資料」變成了「被執行的指令」。

這裡我得誠實劃一條線,因為這正是很多轉述會失手的地方。Mindgard 公開的是「觀察到的行為」,不是 Cursor 內部完整的解析演算法。所以:

  • 已證實:Windows 上用 Cursor 打開含惡意 git.exe 的 repo,那支檔案會被自動執行。
  • 最後驗證環境:2026-04-30,Cursor 3.2.16,Windows。
  • 尚未公開:完整的搜尋順序、最早受影響的版本、以及「機器上已經在標準路徑裝了正版 Git」時是否仍會中招。這些條件很可能直接決定哪些人會踩到。

我不打算替 Mindgard 腦補一套它沒公布的演算法。能拿來當背景參照的,是 Windows 一般的程式啟動語意——先講在前面,這是通則、不等於 Cursor 這次的確切機制:在 Windows 上,當你用一個沒帶完整路徑的相對名稱(git 而不是 C:\Program Files\Git\cmd\git.exe)去啟動程式,作業系統的搜尋規則裡歷來就把呼叫端的當前目錄算在內,執行 git 時也會自動補上 .exe。而你打開 repo 時,當前目錄很可能就是那個 repo。只要 Cursor 的 git 解析在某個環節落進了這類「照當前目錄找」的行為,惡意 git.exe 就正好埋伏在那條路上。

這在資安領域是個有名字的老問題,叫 binary planting,或更廣義的 search order hijacking。DLL 也有一模一樣的版本:程式載入函式庫時如果把當前目錄放進搜尋順序,攻擊者塞一個同名 DLL 就能劫持。差別只在這次的載體是一個「你主動 clone 下來、主動打開」的資料夾。信任邊界整個錯位了——你以為打開資料夾等於讀取內容,實際上這個資料夾裡藏著會被執行的東西。

為什麼這是 Windows 專屬的坑

同一個 repo 拿到 macOS 或 Linux 上打開,這招基本上不成立。真正的分水嶺只有一條:當前目錄該不該出現在程式搜尋路徑裡。

Unix 系統用 PATH 環境變數找程式,而 Unix 的長年慣例是絕對不把 .(當前目錄)放進 PATH——這條規矩老到可以追溯回早年的多使用者主機,就是為了防止有人在共用目錄丟一個假的 ls 坑掉別人。只要 PATH 不含當前目錄,repo 裡那個同名執行檔就排不進搜尋順序,自然輪不到它。(如果你自己手賤把 . 加進 PATH,那另當別論,但那是你把防線拆了。)

有兩個看起來像防線、其實靠不住的因素,順便講清楚免得誤會:

一個是 executable bit。你可能以為 Unix 上檔案沒 chmod +x 就跑不起來,攻擊者總得受害者手動加權限吧?不是。Git 會把 executable bit 一起記進版本控制,攻擊者在自己 commit 的時候就能把檔案標成可執行,clone 下來就是帶著執行權限的。所以這不是防線。

另一個是副檔名。Windows 靠 .exe 這類副檔名認可執行檔,啟動 git 時自動去試 git.exe;但 .bat.cmd 這種其實要透過 cmd.exe 之類的 shell 才會跑,不是隨便撞上就執行。真正讓這次攻擊成立的關鍵不是副檔名花樣,還是回到那條「當前目錄進了搜尋路徑」。

結論很簡單:混合作業系統的團隊裡,用 Windows + Cursor 的成員就是這條攻擊鏈目前最主要的落點(Mindgard 沒公布完整的跨平台測試矩陣,但原理上 Unix 這關本來就難過)。

你現在能做的防護

官方修補之前,防線得自己拉。先給處在風險裡的人可執行的動作,倫理討論放後面。

個人開發者:陌生 repo 一律丟進拋棄式環境

任何來路不明的 repo——別人私訊給你的、GitHub 上隨手 clone 的、面試考題給的——都不要直接用日常那個 Cursor 打開。丟進 Windows Sandbox,或一個隨時可以砍掉重建的隔離 VM,就算在裡面爆炸了,對宿主機的影響也能壓到很低。

要注意 Windows Sandbox 預設是開網路、開剪貼簿共享的,直接拿來跑惡意程式等於給它一條對外的線。處理陌生 repo 時,用一份 .wsb 設定檔把網路和剪貼簿關掉、把宿主的 repo 以唯讀方式映射進去,會安全得多。

想大致摸一下自己這台機器的狀況,有個零成本的自查:在一個你信得過的專案裡,叫出 Cursor 的「Git: Show Git Output」,看它實際採用的 git 路徑指向哪。指到 C:\Program Files\Git\ 底下的正版,至少代表這個工作階段選對了;指到 workspace 裡就危險。但要講清楚,這只是當下這個 session 的診斷、不是免疫證明——換一個惡意 workspace,解析結果不保證一樣,它證明不了「這台機器永遠安全」。

再退一步,養成 clone 完、打開前先掃一眼根目錄的習慣。一行 PowerShell 就夠(我實際用的更隨手,這是整理成能直接貼的版本):

1
2
3
# 純原始碼專案的 repo 裡,本來不該躺著這些東西
Get-ChildItem -Recurse -Include *.exe,*.bat,*.cmd,*.ps1,*.dll |
Select-Object FullName, Length, LastWriteTime

根目錄冒出一個 git.exe 就是明擺著的紅旗。這招擋不住藏得更深的花樣,但足夠擋掉這次這種「一個假 git 擺在門口」的低級攻擊。

企業/團隊:用 AppLocker 針對性封鎖,別一刀切

企業端可以用 AppLocker 或 Windows App Control 擋掉從專案目錄執行的程式,但重點是要針對性,不要一時興起把整個 repo 樹底下的 .exe 全禁掉——那會連編譯輸出、測試執行檔、vendored toolchain、node_modules 裡的原生工具一起打死,災情比漏洞還大。

針對這個漏洞的低干擾臨時規則,應該先只鎖 git.exe

  • Rule collection:Executable Rules
  • Action:Deny
  • User/Group:實際的開發者群組,別套全公司
  • Path condition:開發者 clone 目錄底下的 git.exe,依你們實際路徑調整(例如 C:\Dev\Repos\*\git.exe
  • 先用 Audit only 模式部署,觀察 AppLocker event log 有沒有誤傷,確認沒問題再切 Enforce
  • Test-AppLockerPolicy 拿實際帳號和實際路徑驗一遍再上線

要注意 deny rule 會蓋過 allow rule,沒測過就全公司套下去很容易把人擋在門外。「封鎖整個 workspace 的所有執行檔」是一條需要先盤點的長期政策,不是這次的急救措施。

如果想事後回溯有沒有被打過,查 Sysmon Event ID 1 或 Windows 4688 的程序建立紀錄,找父程序是 Cursor.exe、而映像路徑落在 repo 目錄內的執行。前提是你事前就開了程序建立稽核——沒開的話,這種一閃而過的執行基本上沒有可靠的事後判定方法。

通報七個月,然後 Mindgard 選擇公開

技術的部分到這就講完了,根因不複雜,是個教科書等級的老問題。真正讓我皺眉的是揭露這段。

把時間軸攤開:

  • 2025-12-15:Mindgard 發現漏洞,寄信到 security-reports@cursor.com 通報。
  • 2026-01-15:一個月沒有實質進展,在對方 CISO 介入後改走 HackerOne 正式提交。
  • 2026-01-16:先被以「不在範圍內」關掉,之後又重新打開、確認了漏洞。
  • 2026-0204:多次追問進度。
  • 2026-04-30:最後一次實測,確認 Windows 上的 3.2.16 版依然中招。
  • 2026-06:Mindgard 透過 HackerOne 啟動公開揭露程序(6/1 通知、6/3 收到 HackerOne 的揭露指引)。
  • 2026-07-14:公開完整揭露(full disclosure)。

從通報到最後一次實測,這個洞跨越了非常多次版本發布——Mindgard 自己文中的版本數字還前後兜不攏(一處寫「197+」、一處寫「70+」),但不論採信哪個,跨這麼多次發布都沒修是事實。它也始終沒有拿到自己的 CVE 編號。(如果你去查「Cursor 0day」撞到 CVE-2026-26268,那是另一個透過 Git hooks 觸發的 Cursor 漏洞,已經有編號、也修掉了——跟這裡的 binary planting 是兩回事,後者到目前為止沒查到公開的 CVE。)

公開前一天,也就是 7 月 13 日,Cursor 才對 Dark Reading 表態:「我可以確認我們正在處理,會再跟 Mindgard 聯繫。」而 Mindgard 這邊的說法是,到 7 月 14 日公開為止,沒有收到任何修補完成的通知。他們的產品長 Aaron Portnoy 講得更直接:就算沒有原始碼,他靠逆向工程也大概五分鐘就能修好那一行改動,「12 月就報了,到現在還沒修,我實在想不通」。

完整揭露這件事沒有乾淨的答案。把攻擊細節攤在陽光下,等於也遞了一份現成的食譜給壞人,這個代價是真的。但要求研究者無限期替一個不回應的廠商保密、把使用者蒙在鼓裡,同樣說不過去——使用者連「這個風險存在、我該小心」都不知道,連自保的機會都沒有。Mindgard 那句話講得很重:繼續把資訊壓著,「已經不是在保護使用者,只是在維護沉默」。協調式揭露的前提是雙方都在場,當協調方消失了,剩下的選項本來就不好看。

這件事跟我之前寫過的乾淨 repo 誘導 Claude Code 開反向 shell是同一個家族的兩張臉——那篇靠 prompt injection 騙 AI「太想幫你」,這篇連 AI 都不用騙,純粹是編輯器找執行檔的邏輯有洞。兩條路完全不同,通往的卻是同一句話。

最後

這個洞技術上一點都不高明,就是個當前目錄不該進搜尋路徑的老錯誤,換到 AI 編輯器的皮上重演一次。真正扎心的是它提醒我:我對「打開專案」這個動作的信任,是憑感覺給的,從來沒驗證過底下到底發生了什麼。

我用 Windows 開發,也 clone 過數不清的陌生 repo,過去從沒把「打開資料夾」跟「執行程式」畫上等號。現在會了。下次再 clone 一個不認識的 repo,我大概會先想一下它的根目錄有沒有一個叫 git.exe 的東西在等我——這個念頭有點累人,但總比開一屏小算盤才想起來好。