在 Windows 上打開一個陌生的 Cursor 專案,如果 repo 根目錄裡藏著一個叫 git.exe 的假程式,使用者什麼都還沒按,它就已經開始執行——而且只要專案保持開啟,這個假程式會被一次又一次重新叫起來,不是點一次就結束。
Cursor 會自動執行 repo 裡的 git.exe——當全面揭露成了唯一防線
資安公司 Mindgard 在部落格文章裡把這顆漏洞的技術含量講得很白:這不是一條需要好幾頁解釋的複雜漏洞鏈,而是一個任何工程師看一眼就懂的簡單錯誤——問題不在漏洞本身有多深,而在 Cursor 得知這件事之後的半年裡發生了什麼。這篇文章發布於 2026 年 7 月 14 日,台灣的 gslin 部落格隔天轉載,補了幾句在地工程師的觀察;兩篇合起來讀,正好把「技術上多簡單」跟「回應上多困難」擺在一起看。
一個誰都能重現的 bug
Mindgard 原文開門見山:「This bug is simple. A developer opens a repository in Cursor on Windows, and if that repository contains a malicious git.exe in the project root, Cursor will execute it automatically. There are no clicks, prompts, approval dialogs, or warnings. The result is arbitrary code execution.」翻成白話就是:受害者不需要按下任何東西,Cursor 會自己把這顆假的 git.exe 當成正牌 git 執行,結果是拿到當前使用者權限下的任意程式碼執行能力。「Arbitrary code execution」在這裡不是誇飾語——字面上的意思是攻擊者選的任何指令都能跑。在使用者權限下,這足以讀寫使用者能存取的檔案、竊取儲存在本機的憑證或 token,甚至以這台機器為跳板去接觸內部網路的其他系統;這不是「資料可能外洩」的推測性風險,而是「攻擊者已經拿到執行權,接下來能做什麼只受限於使用者權限」的既成事實。
問題出在 Cursor 找 git 執行檔的方式。文章描述的機制是:「When loading a project, Cursor attempts to locate Git binaries across multiple locations. One of those locations includes the workspace itself.」也就是說,載入專案時 Cursor 會在好幾個地方找 git 執行檔,而 workspace(也就是 repo 根目錄)本身就是其中一個候選位置。文章沒有列出完整的搜尋順序,也沒有交代這些位置彼此的優先次序,但效果是明確的:只要 repo 根目錄放了一個叫 git.exe 的檔案,Cursor 就會找到它、執行它——不管使用者原本裝的是哪一套系統 git,也不管那套系統 git 裝在哪裡。對一個習慣把「開啟陌生 repo」當成無害動作的開發者來說,這個假設本身就被打破了:repo 裡的檔案不再只是「等你手動執行的東西」,有一類檔名會被工具自己找出來執行。下面這張圖把這個決定點攤開來看,切換「根目錄有沒有偽造的 git.exe」,看 Cursor 實際上會叫起哪一個執行檔。
文章沒有解釋為什麼 workspace 根目錄會被列入 git 執行檔的搜尋路徑——這裡合理的推測是,這類設計通常是為了支援「repo 自帶特定版本 git 工具鏈」的情境,例如某些 monorepo 會鎖定特定 git 版本一起提交進版控。但 Mindgard 的報告沒有證實這個猜測,只確認了實際效果:一旦把這個位置放進搜尋順序,信任邊界就跟著破了。
切換根目錄狀態,看 Cursor 實際執行哪一個 git · 兩種情境
把攻擊面攤開來看,這顆漏洞不需要複雜的利用鏈,也不需要繞過任何確認機制——因為根本沒有機制可繞。攻擊者要做的事只有一件:把一個檔案取名叫 git.exe,塞進一個看起來無害的 repo 根目錄,等著有人在 Windows 上用 Cursor 打開它。這類漏洞在資安圈有個熟悉的名字:binary planting,也是早期 Windows 上「DLL 搜尋路徑劫持」的同一種邏輯——工具在檢查受信任的系統路徑之前,先去看了一個使用者可控的目錄,攻擊者只要能把檔案放進那個目錄,就等於拿到了工具本身的執行權。差別在於,這次被劫持的不是 DLL,而是整個 git 執行檔;放檔案的方式也不需要任何權限提升,只要受害者願意 clone 或下載一個 repo,攻擊者的檔案就自動跟著進來了。
近年 AI 編輯器把「開啟陌生 repo、讓 agent 讀懂整個專案」當成日常操作,這個假設——repo 內容是可以信任著去讀、去分析的——正是這顆漏洞踩碎的地方。像 Cursor 這類 AI coding assistant,日常運作本來就會在背景頻繁呼叫 git:讀分支狀態、算 diff、餵給模型當 context,使用者完全不會意識到這些呼叫正在發生。對這顆漏洞來說,這件事本身就是舞台——受害者不需要自己手動打一次 git status,只要把專案開著讓 agent 工作,執行的機會就會自動出現,而且是反覆出現。
這種「repo 裡的內容本身能觸發執行」的風險,其實不是全新的類別。npm 的 postinstall script、Python 套件的 setup.py,都曾經是同一種邏輯下的攻擊面——差別在於,那些管道至少還算是套件管理工具已知的功能,開發者理論上知道要提防;Cursor 這裡曝露的路徑,卻是使用者原本以為單純是「開啟資料夾」的動作,完全沒有心理準備。對外包協作或開源貢獻頻繁的團隊來說,這件事的實務意義更直接:pull request 裡新增的檔案清單,向來不是 code review 會逐一核對的項目——審閱者盯著的是程式邏輯的差異,不會去確認 repo 根目錄下多了一個叫 git.exe 的陌生檔案。
不是一次性攻擊
Mindgard 的 PoC 附上了 Sysinternals Process Monitor 的紀錄,畫面裡跳出一連串小算盤視窗。文章特別強調:「the multiple Calculator windows were not opened manually by the researcher. Cursor continued to re-execute the renamed binary while the project was left open, causing more instances to appear over time.」小算盤視窗不是研究員手動開的,是 Cursor 在專案保持開啟期間反覆重新執行那個被改名的執行檔,隨著時間累積出愈來愈多視窗。
這一點改變了威脅模型的形狀。一次性的程式碼執行已經夠嚴重,但「只要專案還開著就會反覆觸發」意味著攻擊者不需要精準抓住某個瞬間——只要受害者把專案留在背景視窗裡繼續工作,惡意程式碼就有無數次重新執行的機會,每一次都不需要使用者多做任何動作。下面這個模擬把這個行為的形狀畫出來:按下開始,看重複執行次數如何隨模擬時間累積。
按下開始,看重複執行次數如何隨模擬時間累積 · 可暫停與重置
依 Mindgard PoC 描述繪製的示意動畫,不是原始測試量到的真實秒數——原文只確認「專案保持開啟」是持續觸發的…
只要 Cursor 專案保持開啟,被植入的 git.exe 就會反覆重新執行,不是單次攻擊;畫面裡的視窗數量只會隨時間增加,直到專案關閉為止。
持續觸發這件事,也改變了防守方需要考慮的時間尺度。單次執行的漏洞,防守方只要抓住那一個瞬間——例如即時掃描剛好在那一刻攔下——風險就過去了;但只要專案沒關,攻擊者的程式碼就有無限次重新執行的機會,防守方得抓住每一次才算安全,攻擊者卻只要抓住一次就夠。這種不對稱,正是 Mindgard 把 PoC 重點放在「反覆出現的小算盤視窗」而不是「單次執行」的原因。多數端點防護(防毒、EDR)的預設假設是「威脅只出現一次,抓住那一次就結束了」;持續重複觸發的行為打破了這個假設——小算盤視窗一個接一個跳出來,比任何文字說明都更直接地告訴讀者:這不是理論上的風險,而是持續發生的事。如果受害的不是工程師自己的筆電,而是跑在背景、長時間開著同一個 workspace 的自動化 agent 或 CI runner,這種持續觸發的特性會被進一步放大——沒有人盯著螢幕看有沒有異常視窗跳出來,惡意程式碼反而更有機會不被發現地重複執行很長一段時間。
報告裡另外附了一個技術細節,容易被忽略但值得記下:文章寫的是「last verified on April 30, 2026 against Cursor version 3.2.16 on Windows」——這是最後一次驗證的時間與版本,不是一份「受影響版本清單」。文中沒有交代這顆漏洞是從哪個版本開始出現,也沒有說目前是否有其他分支已經修正;換句話說,讀者不該把 3.2.16 讀成「只有這個版本中鏢」,文中未指明完整的受影響版本範圍。這種「只寫最後驗證版本」的寫法,在資安報告裡並不少見——持續驗證每一個歷史版本的成本很高,研究者通常只確認「目前這個版本仍然有問題」,不會反向追溯漏洞何時被引入。讀者若想知道自己用的版本是否受影響,目前唯一可靠的做法是自己動手測試,而不是對照版本號碼去猜。
半年、三個管道、一次次石沉大海
技術漏洞本身只是故事的一半。Mindgard 一開始走的是最正規的路線:「Initial disclosure was sent directly to Cursor's security reporting e-mail address, as specified in the company's published security.txt file.」照著 Cursor 自己公開的 security.txt 指定信箱送出回報,三天後追蹤確認是否收到——兩次都沒有下文。接下來一個月,Mindgard 換了管道:在 LinkedIn 上公開發文,想找到 Cursor 內部能接手的人,這一步才輾轉牽出 CISO。
時間線裡寫的是:「Cursor CISO responds to the e-mail thread indicating an automation failed that was supposed to invite to the HackerOne private bounty program. CISO manually invites Mindgard to the bounty program.」CISO 的說法是自動化流程失效,原本該發出的 HackerOne 邀請沒有寄出,於是手動補發邀請。這個說法本身沒有被獨立驗證——文章只記錄了 Cursor 這一方給出的解釋,沒有進一步追問這套自動化平常運作得怎麼樣、是不是只有這次回報恰好撞上故障;這一點,讀者可以自行判斷要不要照單全收。照著新管道送出的回報,結果卻是:「The report was initially closed as Informative and out of scope.」被判定為僅供參考、不在處理範圍內。Mindgard 提出申覆之後,「After we challenged that determination, HackerOne reopened the report, reproduced the issue, and confirmed that the details had been delivered to Cursor.」報告重新開啟,HackerOne 自己重現了問題,並確認細節已經轉交給 Cursor。到這一步,漏洞的存在與可重現性都已經不是爭議點。
在漏洞獎勵平台的慣例裡,「Informative」這個分類通常保留給已知問題、重複回報,或者確認不構成安全風險的情況。把一份已經附上 Process Monitor 紀錄、能重現任意程式碼執行的回報放進這個分類,等於一開始就把它擋在正式處理流程之外。這也是為什麼 Mindgard 選擇提出申覆,而不是接受這個結論——申覆成功、HackerOne 親自重現問題,某種程度上等於證實了第一次的分類本身站不住腳。資安圈子沒有統一規定要等多久才能公開,但不少研究機構奉行的默契是九十天;Mindgard 在這裡等的時間,遠遠超過這個一般認知的門檻,而且中間還夾著一次「已被判定不成立」又被推翻的插曲。
接下來的幾個月,才是真正磨人的部分。下面這份時間線把每一次追蹤攤開,可以看到大多數格子填的都是同一件事:沒有回應。
點選任一階段看細節 · 6 個階段跨度約半年
六個階段,一次次石沉大海
依 security.txt 指定信箱送出回報,三天後追蹤確認是否收到——兩次都沒有下文。
email 沒人接手,Mindgard 轉往 LinkedIn 公開發文找內部窗口,這一步才輾轉牽出 CISO。
CISO 坦承自動化流程失效、手動邀入 HackerOne;報告先被判 informative and out of scope,申覆後重新開啟並確認可重現。
HackerOne 確認漏洞細節已經轉交給 Cursor——存在與可重現都不再是爭議點。
2/16、3/3 常規追問、3/17 直接聯繫 CISO 本人、4/1 再追問一次——HackerOne 每次的答案都是沒有更新。
通知 HackerOne 即將公開、取得揭露指引;七月中發布全面揭露文章。
從一月中的重新開啟,到六月初 Mindgard 告知平台即將公開揭露為止,中間橫跨了三個管道——email、HackerOne 報告串、CISO 本人——沒有一個管道給出實質進展。台灣的部落格 gslin 在轉載這篇報告時,把這條時間線濃縮成一句話:「從時間線可以看到 Cursor 要求 Mindgard 在一開始的 e-mail 回報管道被無視 (被推託說是自動化程序失效),後續被 CISO 要求到 HackerOne 上面回報,結果 Cursor 的人在看過回報後先是說 Informative and out of scope,然後經過 Mindgard 再次挑戰後,被 HackerOne 認定漏洞存在、可重製,然後甚至透過 HackerOne 再去跟 Cursor 接觸也被無視,於是最後公開。」三個管道各自失效一次不算巧合,是同一種結果重複發生三次。gslin 的轉載本身沒有增加新事實——內容幾乎全部忠實摘自 Mindgard 原文——但它把這起事件放進中文技術圈的視野;對本地工程團隊來說,這類轉載往往是第一次接觸到原始報告的管道,也是判斷「這件事嚴不嚴重」的第一手依據。
揭露的兩難,以及企業能做什麼
Mindgard 在文章裡先表態自己的立場:「Like many security research teams, Mindgard prefers coordinated disclosure.」跟大多數資安研究團隊一樣,他們更偏好協調揭露,而不是一開始就公開。但協調揭露有一個前提:「Full disclosure is the nuclear option of vulnerability disclosure, reserved for situations where every other path has failed.」全面公開是揭露光譜裡的核選項,只留給每一條路都走不通的情況——標題裡那句「when full disclosure becomes the only protection left」,字面意思就是:公開,是使用者還能得到的唯一保護。「協調揭露」的常見做法是:研究者先私下通知廠商、給一段修補時間、雙方談好一個公開的時間點,讓使用者在漏洞細節公開的同時,也已經有更新可以裝。這套機制能運作,前提是廠商真的會在期限內回應、修補;一旦廠商連「有沒有在處理」都不肯說,研究者手上剩下的選項就只有「繼續等」或「公開」兩種,而「繼續等」對已經暴露在風險裡的使用者並不公平。
gslin 在轉載這篇報告時,補了一句在地工程師會有的直覺反應:「以現在軟體的複雜度來說,有洞在所難免 (即使是很蠢的洞),但整個回報的流程失效就很大條了...」漏洞本身或許只是運氣不好,任何複雜軟體都難免有蠢洞;但三個管道都無法讓 Cursor 給出實質回應,這件事的嚴重程度不亞於漏洞本身,甚至更值得留意——因為它決定了下一個回報者會不會得到不同的結果。
Mindgard 收尾時把責任攤得很直接:「Trust requires accountability, and accountability requires communication. When users, researchers, and disclosure platforms spend months seeking basic status updates without success, that accountability becomes difficult to see or believe in.」信任建立在可問責之上,而可問責建立在溝通之上;當使用者、研究者、揭露平台花上好幾個月要一個基本的狀態更新都要不到,這份可問責就很難讓人相信。文章也順帶點出這件事的規模:「Given that Cursor is one of the most widely adopted AI-assisted development environments (7 million+ active users, 1 million+ daily, 1 million+ paying, used by 50K+ companies), and its reported market price of $60 billion, it's fair to assume that some level of respect for security practices exists, but this issue would indicate otherwise.」照 Mindgard 自己的說法:一家市值六百億美元、有七百萬以上活躍用戶的公司,照理該有相應的資安應對能力,但這個案例顯示的是相反的結果。
在漏洞還沒修正之前,Mindgard 給了兩種讀者不同的建議。個人開發者這邊很直接:「Until the IDE is patched, open untrusted repositories only in an isolated VM, Windows Sandbox, or other disposable environment.」在 IDE 修正之前,不熟悉的 repo 只在隔離的 VM、Windows Sandbox 或其他可拋棄環境裡開啟。企業 IT 這邊給的是可以馬上落地的政策文字:「As a temporary mitigation on managed Windows systems, administrators can use AppLocker or Windows App Control policies to deny execution of the affected executable name from developer workspace directories. Prefer path-based deny rules scoped to repo/workspace roots, such as %USERPROFILE%\source\repos\*\filename.exe, rather than hash-based rules, because attacker-supplied binaries can vary by hash. Windows does not provide a general built-in rule to block an arbitrary child executable only when launched by a specific parent process, so parent-aware enforcement generally requires EDR or a custom endpoint security product.」用路徑規則擋掉「repo 根目錄底下的執行檔」,而不是用雜湊規則,因為攻擊者可以任意換掉雜湊;真的要做到「只擋掉被特定父行程叫起的子行程」,得靠 EDR 或客製化端點防護,Windows 本身沒有內建這種規則。下面這張圖把三層防線疊在一起看:
值得提醒的是,Mindgard 描述的攻擊路徑集中在 Windows 上 git.exe 的搜尋行為,文章沒有交代 macOS 或 Linux 上是否存在對應的問題——讀者不該把這篇報告直接套用到其他作業系統。如果團隊裡有工程師在 Windows 上用 Cursor 開外部或第三方的 repo,這是這週就能檢查的事:有沒有部署 AppLocker 或 Windows App Control、平常開新 repo 前有沒有先看過根目錄裡的可疑執行檔、CI 機器是不是也用同一套 IDE 自動化開專案。這些都是文章給的暫時建議可以立刻落地的地方,不需要等 Cursor 官方修補。
這起事件也丟給採用 AI coding assistant 的團隊一個沒有捷徑的問題:導入這類工具時,安全稽核的範圍不能只停在「這個工具會不會外洩我的程式碼」,還得包含「這個工具本身有沒有意願好好處理資安回報」。Mindgard 的時間線提供的是後者的一個具體樣本,而不是抽象的信任評分。
值得留意的是,這三層建議全部標明是「暫時」:路徑規則會被繞過(只要攻擊者換個檔名策略),VM/Sandbox 也只是把風險隔離而不是消除,EDR 的父行程感知則要另外採購與維運能力,不是所有團隊都負擔得起。Mindgard 在文章結尾沒有給出「問題已解決」的訊號——截至發文當下,這顆漏洞仍未修正,讀者能做的就是這三層裡挑得動的那幾層。
從 12 月中的第一封信到 7 月中的全面揭露,Mindgard 用掉的不只是半年時間,還有三個管道各自被無視一次的耐心;這段耐心用完之後剩下的,就是這篇文章。
Closing thought:全面揭露不是 Mindgard 的第一選擇,而是三個管道都試過半年之後,唯一還能留給使用者的保護——文章發布的當下,漏洞仍未修正,能做的緩解只剩路徑規則與隔離環境這兩件事。