為本機代理實作安全沙盒環境

Ani Betts, Yash Gaitonde & Alex Haugland研究
為本機代理實作安全沙盒環境

程式撰寫代理在執行終端機指令以探索環境並進行變更方面,能力已大幅提升。自動核准這些指令的使用者,能啟用功能強大得多的代理,但代價是風險升高。出錯的代理可能刪除資料庫、提交有問題的程式碼,或外洩機密。

要求對每一道指令都進行人工核准可以降低這些風險,但往往只能暫時奏效。當核准請求累積到一定程度,使用者就不再仔細檢查。當工程師同時執行多個代理,還必須在不同核准提示間切換時,情況會更嚴重。結果就是產生「核准疲勞」,反而削弱了核准機制本身的意義。

在過去三個月中,我們透過在 macOS、Linux 與 Windows 上推出代理沙盒機制來解決這個問題。被沙盒保護的代理可在受控環境中自由運作,只有在需要走出該環境時(多半是要存取網際網路)才會要求核准。

這大幅減少了中斷。與未沙盒化的代理相比,沙盒代理需要停下來的次數少了 40%,為使用者節省了大量手動檢查與核准的時間。

被沙盒保護的代理停止運作的次數比未沙盒化的代理少 40%被沙盒保護的代理停止運作的次數比未沙盒化的代理少 40%

我們的沙盒目標

我們開始著手沙盒化時的目標,是在提升安全性的同時避免中斷。我們希望在拒絕會帶來風險的權限之餘,仍然賦予 Agent 足夠的空間,讓它們能有效運作。

要拿捏這個平衡比想像中困難。許多終端機指令即使只是執行基本的測試或建置步驟,也會需要一些意想不到的額外權限。過於單純的沙盒設計會封鎖這些權限,進而破壞 Agent 的工作流程。設計一個可用的沙盒,是在各作業系統既定條件下,在安全性與可用性之間不斷權衡取捨的過程。

實作

我們提供了一個統一的 sandbox API,但在各個平台上的實作方式各不相同。macOS、Linux 和 Windows 各自提供不同的 sandboxing 基本機制,這些差異形塑了底層的設計決策。

macOS

我們在 macOS 上評估了四種沙箱化方法:App Sandbox、容器、虛擬機器,以及 Seatbelt。App Sandbox 是為 Mac App Store 設計的,並且會要求 Cursor 對代理可能執行的每一個二進位檔進行簽名。這不僅會大幅增加複雜度,還會因為允許代理產生或修改的二進位檔繼承 Cursor 的信任,而開啟新的濫用途徑。容器會讓我們只能使用 Linux 二進位檔,而虛擬機器則會帶來無法接受的啟動延遲與記憶體開銷。

因此我們選擇透過 sandbox-exec 使用 Seatbelt。它在 2007 年引入,並在 2016 年被標記為已棄用,但仍被 Chrome 等關鍵第三方應用程式使用。它允許在沙箱設定檔下執行指令,藉此限制整個子行程樹的行為。

這個設定檔以細粒度定義權限,透過一種帶有自身特色的策略語言,限制系統呼叫以及對特定檔案與目錄的讀寫。我們會在執行階段,依據工作區層級與管理員層級設定,以及使用者的 .cursorignore 動態產生這份策略。

(deny file-write* (regex "^.*\/\\\.vscode($|\/.*)")
)
(deny file-write* (require-all
    (regex "^.*\/\\\.cursor($|\/.*)")
    (require-not (regex "^.*\/\\\.cursor/(rules|commands|worktrees|skills|agents)($|\/.*)")))
)
(deny file-write* (regex "^.*\\\.code-workspace$"))
(deny file-write* (regex "^.*\/\\\.cursorignore$"))
(deny file-write* (regex "^.*\/\\\.git/config$"))
(deny file-write* (regex "^.*\/\\\.git/hooks($|\/.*)")
)
(deny file-write* (regex "^(/private)?/var/folders/.*-cursor(-[a-z]+)?-zsh($|\/.*)")
)

Linux

相較於 macOS,Linux 一方面更簡單,一方面又更棘手。核心透過 Landlockseccomp 提供所需的基礎機制,但必須由使用者空間來把它們組合成一個可用的沙箱。雖然有多個開源專案已有效結合這些機制,但沒有一個支援像 .cursorignore 這樣的功能。

我們決定直接使用 Landlock 和 seccomp。Seccomp 會封鎖不安全的系統呼叫,而 Landlock 則強制執行檔案系統限制,讓我們可以讓被忽略的檔案對沙箱中的程序完全不可存取。我們將使用者工作區對應到一個 overlay 檔案系統,並以受 Landlock 保護的副本覆寫被忽略的檔案,使其無法被讀取或修改。

尋找並重新掛載這些檔案是 Linux 沙箱化中最慢的部分。如果能像 macOS 那樣以 lazy 的方式延遲過濾檔案系統操作會更容易,但 Linux 並未在 seccomp-bpf 的情境中提供方便存取檔案路徑的方式。

Windows

在 Windows 上,我們會在 WSL2 中執行我們的 Linux 沙箱。要建立一個具備同等能力的原生 Windows 沙箱困難得多,因為現有的大多數沙箱基礎機制都是為瀏覽器設計的,並不支援通用型的開發者工具。我們正與 Microsoft 合作,確保所需的這些基礎機制能夠提供並可供使用。

教導代理如何使用沙盒

只有在代理能預判哪些指令會在沙盒中成功執行,並能辨識何時需要提升權限時,沙盒才真正有效。要讓模型具備沙盒感知能力,我們必須調整代理的 harness。

我們先更新了 Shell 工具的描述,來說明沙盒的限制條件:依照使用者設定,指令是否能存取檔案系統、git 或網路,以及代理在需要時如何請求更高權限。要得到一個我們滿意、可作為基準的 harness 變更,需要進行大量手動測試——我們會執行幾個常見的 rollout 流程,觀察哪裡和預期不符,微調提示詞,然後再跑一次 rollout。

接著,我們使用內部的基準測試 Cursor Bench 來評估這些變更的影響,比較有啟用和未啟用沙盒的代理。很快我們就注意到一種常見的失敗模式:代理會一再重試同一個終端機指令,卻不變更權限。

為了解決這個問題,我們更新了 Shell 工具結果的呈現方式,明確顯示導致失敗的沙盒限制條件,並在某些情況下建議代理提升權限。在推出這些提醒之後,代理從與沙盒相關的失敗中恢復得更為順暢,而離線評測表現也大幅提升。

不過,離線評測只反映了整體情況的一小部分。為了進一步確保沙盒不會降低使用者體驗,我們在正式環境中逐步推出沙盒功能。我們從內部與外部收到的回饋,都讓我們對正式釋出這個功能更有信心。現在,在受支援的平台上,大約有三分之一的請求是透過沙盒執行,我們也已導入許多企業客戶,例如 NVIDIA

當代理從單純產生程式碼,進一步跨入操作正式環境系統時,提供明確的執行邊界就變得至關重要。我們目前的實作是朝這個方向邁出的一步。接下來,我們特別期待在原生支援沙盒的環境中訓練代理,讓它們了解所在環境的限制。這樣的代理可以被賦予更大的自由,直接撰寫腳本與程式,而不僅僅侷限於呼叫工具。

如果你有興趣投入處理與程式開發未來相關的深度技術難題,歡迎透過 hiring@cursor.com 與我們聯絡。

歸檔於: 研究

作者s: Ani Betts, Yash Gaitonde & Alex Haugland

為本機代理實作安全沙盒環境 · Cursor