ローカルエージェント向けの安全なサンドボックスの実装

by Ani Betts, Yash Gaitonde & Alex Haugland研究
Implementing a secure sandbox for local agents

コーディングエージェントは、環境を探索したり変更を加えたりするためにターミナルコマンドを実行する能力が大きく向上しています。これらのコマンドを自動承認すると、エージェントははるかに強力になりますが、その分リスクも増大します。誤った動作をするエージェントは、データベースを削除したり、不具合のあるコードをデプロイしたり、シークレットを漏洩させたりする可能性があります。

すべてのコマンドに対して人間の承認を要求すれば、そのリスクは軽減できますが、多くの場合それは一時的なものに過ぎません。承認が積み重なるにつれ、ユーザーはそれらを注意深く確認しなくなっていきます。複数のエージェントを並行実行し、承認プロンプト間でコンテキストスイッチしなければならない状況では、なおさら悪化します。その結果生じるのが「承認疲れ」であり、そもそもの承認プロセスの意義を損なってしまいます。

過去3か月間で私たちは、macOS・Linux・Windows 上でエージェントのサンドボックス機能を展開することで、この問題に取り組んできました。サンドボックス化されたエージェントは制御された環境内で自由に動作し、その外に出る必要がある場合、もっとも多いケースとしてはインターネットへのアクセス時にだけ、承認を要求します。

これにより中断は大幅に減少します。サンドボックス化されたエージェントは、サンドボックス化されていないエージェントと比べて停止する頻度が 40% 低くなり、ユーザーの手動レビューと承認にかかる時間を大幅に削減します。

サンドボックス化されたエージェントは、サンドボックス化されていないエージェントと比べて停止する頻度が 40% 低いサンドボックス化されたエージェントは、サンドボックス化されていないエージェントと比べて停止する頻度が 40% 低い

私たちのサンドボックスの目標

私たちは、作業の中断をなくしつつセキュリティを向上させることを目標に、サンドボックス化の取り組みを始めました。エージェントが十分に能力を発揮できるだけの自由度を与えつつ、リスクを生む権限は付与しないようにしたいと考えました。

このバランスを取ることは、見た目以上に難しい課題です。多くのターミナルコマンドは、基本的なテストやビルド手順であっても、予想外の特権を必要とします。単純なサンドボックスだと、こうしたコマンドをブロックしてしまい、エージェントのワークフローを妨げることになります。実用的なサンドボックスを設計することは、各オペレーティングシステムが定める制約の中で、セキュリティと使いやすさのトレードオフのバランスをどう取るかを検討する作業でもあります。

実装

各プラットフォームごとに実装は異なりますが、共通のサンドボックス API を公開しています。macOS、Linux、Windows ではそれぞれ異なるサンドボックス機構が提供されており、それらが基盤となる設計上の判断に影響を与えています。

macOS

macOS では 4 種類のサンドボックス手法、App Sandbox、コンテナ、仮想マシン、そして Seatbelt を評価しました。App Sandbox は Mac App Store 向けに設計されており、エージェントが実行する可能性のあるすべてのバイナリに Cursor の署名を行う必要があります。これは大きな複雑性をもたらすだけでなく、エージェントが生成または変更したバイナリが Cursor の信頼を継承できてしまうため、新たな悪用ベクターも生み出します。コンテナは Linux バイナリに制限され、仮想マシンは許容できない起動遅延とメモリオーバーヘッドを伴います。

この検討の結果、sandbox-exec を通じて利用できる Seatbelt だけが残りました。Seatbelt は 2007 年に導入され、2016 年に非推奨となりましたが、現在も Chrome のような重要なサードパーティアプリケーションで使われています。Seatbelt により、サブプロセスツリー全体の挙動を制約するサンドボックスプロファイルの下でコマンドを実行できます。

プロファイルは、独自のポリシー言語を通じて特定のファイルやディレクトリへの読み書きやシステムコールを制限しつつ、きめ細かな権限を定義します。ワークスペースレベルおよび管理者レベルの設定に加え、ユーザーの .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

Linux は、macOS より簡単な部分もあれば、より難しい部分もあります。カーネルは Landlockseccomp を通じて必要なプリミティブを公開していますが、それらを実用的なサンドボックスとして構成する責任はユーザー空間側にあります。いくつかのオープンソースプロジェクトはこれらの仕組みを効果的に組み合わせていますが、.cursorignore のような機能をサポートしているものはありません。

そこで、Landlock と seccomp を直接利用することにしました。seccomp は安全でないシステムコールをブロックし、Landlock はファイルシステムの制限を強制することで、無視対象のファイルをサンドボックス化されたプロセスから完全にアクセス不能にできます。ユーザーのワークスペースをオーバーレイファイルシステムにマッピングし、無視対象のファイルを、読み取りも変更もできない Landlock 適用済みのコピーで上書きします。

これらのファイルを見つけ出して再マウントする処理が、Linux におけるサンドボックス化の中で最も時間のかかる部分です。macOS のように、ファイルシステム操作を遅延的にフィルタリングできれば簡単なのですが、Linux では seccomp-bpf のコンテキストからファイルパスへ簡単にアクセスする手段が用意されていません。

Windows

Windows では、Linux サンドボックスを WSL2 上で実行しています。これと同等のネイティブ Windows サンドボックスを構築するのははるかに困難です。既存のサンドボックス用プリミティブのほとんどがブラウザ向けに特化しており、汎用的な開発者ツールをサポートしていないためです。必要なプリミティブが利用可能になるよう、Microsoft と協力して取り組んでいます。

サンドボックスの使い方をエージェントに学習させる

サンドボックスが効果を発揮するのは、エージェントがどのコマンドがサンドボックス内で成功しそうかを見極められ、いつ権限昇格が必要になるかを認識できる場合に限られます。モデルをサンドボックス対応にするには、エージェント用ハーネスを変更する必要がありました。

まず、Shell ツールの説明を更新し、サンドボックスの制約を明示しました。すなわち、ユーザー設定に応じてコマンドがファイルシステム、git、ネットワークのどのアクセス権で実行されるか、そして必要な場合にエージェントがどのようにより高い権限をリクエストできるか、といった点です。満足できるベースラインとなるハーネスの変更内容を得るまでには、多くの手動テストが必要でした。いくつかの一般的なロールアウトを実行し、期待と異なる挙動があった箇所に気づき、プロンプトを微調整し、再度ロールアウトを実行する、というサイクルを繰り返しました。

次に、社内ベンチマークである Cursor Bench を用いて、サンドボックスを有効にしているエージェントとしていないエージェントを比較し、これらの変更の影響を評価しました。すぐに、よくある失敗パターンが見えてきました。エージェントが権限を変更することなく、同じターミナルコマンドを何度もリトライしてしまうのです。

これに対処するため、Shell ツールの結果の表示方法を更新し、失敗の原因となったサンドボックス制約を明示的に示し、場合によってはエージェントに権限昇格を推奨するようにしました。こうした注意喚起をリリースした後は、エージェントはサンドボックス関連の失敗からはるかにスムーズにリカバーできるようになり、オフライン評価のパフォーマンスも大幅に改善しました。

とはいえ、オフライン評価だけでは全体像の一部しか分かりません。サンドボックスがユーザー体験を損なわないことをさらに確信するため、本番環境でサンドボックスを段階的にロールアウトしていきました。社内外から寄せられたフィードバックによって、この機能を正式に提供する自信が得られました。現在では、対応プラットフォーム上のリクエストの 3 分の 1 がサンドボックスを有効にした状態で実行されており、NVIDIA のような多くの企業顧客に導入していただいています。

エージェントがコードの生成から本番システムの運用へと役割を広げていく中で、実行境界を設けることは極めて重要です。現在の実装は、そのための一歩にすぎません。今後は、とりわけ、環境の制約を前提に学習されたサンドボックスネイティブなエージェントに期待しています。こうしたエージェントには、ツール呼び出しに限定するのではなく、スクリプトやプログラムを直接記述する自由を与えることができます。

もしコーディングの未来に関わる高度な技術課題に取り組むことに興味があれば、hiring@cursor.com までご連絡ください。

分類: 研究

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

ローカルエージェント向けの安全なサンドボックスの実装 · Cursor