Mettre en place un bac à sable sécurisé pour les agents locaux

Les agents de programmation deviennent beaucoup plus efficaces pour exécuter des commandes dans le terminal afin d’explorer l’environnement et d’y apporter des modifications. Les utilisateurs qui approuvent automatiquement ces commandes débloquent des agents nettement plus puissants, mais au prix d’un risque accru. Un agent qui se trompe peut supprimer des bases de données, livrer du code défectueux ou divulguer des secrets.
Exiger une approbation humaine pour chaque commande atténue ce risque, mais souvent seulement temporairement. À mesure que les approbations s’accumulent, les utilisateurs cessent de les examiner attentivement. Le problème s’aggrave lorsque les ingénieurs exécutent plusieurs agents en parallèle et doivent changer de contexte entre les fenêtres de demande d’approbation. Il en résulte une fatigue liée aux approbations, qui sape l’objectif même de ces approbations.
Au cours des trois derniers mois, nous avons résolu ce problème en déployant le sandboxing d’agents sur macOS, Linux et Windows. Les agents en bac à sable s’exécutent librement dans un environnement contrôlé et ne demandent une approbation que lorsqu’ils doivent en sortir, le plus souvent pour accéder à Internet.
Cela réduit considérablement les interruptions. Les agents en bac à sable s’arrêtent 40 % moins souvent que ceux qui ne le sont pas, ce qui permet aux utilisateurs d’économiser des heures de relecture et d’approbation manuelles.


Nos objectifs pour le sandbox
Nous avons commencé notre travail de sandboxing avec l’objectif d’éliminer les interruptions tout en améliorant la sécurité. Nous voulions fournir aux agents suffisamment de latitude pour être efficaces, tout en leur refusant les permissions à risque.
Trouver ce bon équilibre est plus difficile qu’il n’y paraît. De nombreuses commandes de terminal exigent des privilèges inattendus, même pour des étapes de test ou de build basiques. Un sandbox trop simpliste bloquerait ces commandes et casserait le workflow de l’agent. Concevoir un sandbox vraiment utilisable consiste à arbitrer entre sécurité et ergonomie, tout en travaillant dans les contraintes propres à chaque système d’exploitation.
Implémentation
Nous exposons une API de sandbox unifiée, implémentée différemment sur chaque plateforme. macOS, Linux et Windows offrent des primitifs de sandboxing distincts qui ont guidé la conception sous-jacente.
macOS
Nous avons évalué quatre approches de sandboxing sur macOS : App Sandbox, des conteneurs, des machines virtuelles et Seatbelt. App Sandbox est conçu pour le Mac App Store et exigerait que Cursor signe chaque binaire qu'un agent pourrait exécuter. Cela aurait ajouté une complexité importante et ouvert de nouveaux vecteurs d'abus en permettant à des binaires générés ou modifiés par des agents d'hériter de la confiance accordée à Cursor. Les conteneurs nous limiteraient aux binaires Linux, et les machines virtuelles imposent une latence de démarrage et une consommation de mémoire inacceptables.
Restait donc Seatbelt, accessible via sandbox-exec. Il a été introduit en 2007 et déclaré obsolète en 2016, mais est encore utilisé par des applications tierces critiques comme Chrome. Il permet d'exécuter une commande sous un profil de sandbox qui contraint le comportement de tout l'arbre de sous-processus.
Le profil définit des autorisations avec une grande granularité, en restreignant les appels système ainsi que les opérations de lecture et d'écriture sur des fichiers et répertoires spécifiques via un langage de politique assez particulier. Nous générons cette politique dynamiquement à l'exécution en fonction des paramètres au niveau de l'espace de travail et au niveau administrateur, ainsi que du fichier .cursorignore de l'utilisateur.
(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 est à la fois plus simple et plus complexe que macOS. Le noyau expose les primitives nécessaires via Landlock et seccomp, mais l'espace utilisateur est responsable de les composer en un bac à sable utilisable. Plusieurs projets open source combinent efficacement ces mécanismes, mais aucun ne prend en charge des fonctionnalités comme .cursorignore.
Nous avons décidé d'utiliser directement Landlock et seccomp. Seccomp bloque les appels système dangereux, tandis que Landlock applique des restrictions sur le système de fichiers, ce qui nous permet de rendre les fichiers ignorés complètement inaccessibles au processus isolé. Nous plaçons les espaces de travail des utilisateurs dans un système de fichiers en superposition et remplaçons les fichiers ignorés par des copies protégées par Landlock qui ne peuvent pas être lues ni modifiées.
La recherche et le remontage de ces fichiers sont la partie la plus lente de l'isolation sous Linux. Il serait plus simple de filtrer les opérations sur le système de fichiers de manière différée, comme le fait macOS, mais Linux ne fournit pas un accès facile au chemin du fichier dans un contexte seccomp-bpf.
Windows
Sous Windows, nous exécutons notre bac à sable Linux via WSL2. Construire un bac à sable Windows natif équivalent est nettement plus difficile, car la plupart des primitives de sandboxing existantes sont conçues pour les navigateurs et ne prennent pas en charge des outils de développement généralistes. Nous travaillons avec Microsoft pour que les primitives nécessaires soient disponibles.
Apprendre aux agents à utiliser le sandbox
Un sandbox n’est efficace que si les agents peuvent anticiper quelles commandes réussiront à l’intérieur du sandbox et reconnaître quand une élévation de privilèges est nécessaire. Rendre les modèles sensibles au sandbox a nécessité des modifications à l’infrastructure de l’agent.
Nous avons commencé par mettre à jour les descriptions de l’outil Shell pour expliquer les contraintes du sandbox : selon les paramètres utilisateur, si les commandes s’exécutent avec accès au système de fichiers, à git ou au réseau, et comment l’agent peut demander des autorisations élevées lorsque c’est nécessaire. Obtenir une évolution de base de cette infrastructure dont nous étions satisfaits a exigé beaucoup de tests manuels : nous exécutons quelques déploiements courants, observions où les choses se passaient différemment de ce qui était prévu, ajustions le prompt, puis relancions les déploiements.
Nous avons ensuite évalué l’impact de ces changements en utilisant notre benchmark interne, Cursor Bench, en comparant des agents avec et sans sandbox activé. Nous avons rapidement identifié un mode de défaillance fréquent : l’agent réessayait plusieurs fois la même commande de terminal sans modifier les autorisations.
Pour y remédier, nous avons mis à jour la façon dont les résultats de l’outil Shell sont affichés, en faisant apparaître explicitement la contrainte du sandbox responsable de l’échec et, dans certains cas, en recommandant que l’agent augmente ses autorisations. Après avoir livré ces rappels, les agents se remettaient beaucoup plus facilement des échecs liés au sandbox et les performances des évaluations hors ligne se sont nettement améliorées.
Les évaluations hors ligne ne donnent toutefois qu’une vision partielle de la situation. Pour obtenir une assurance supplémentaire que le sandbox n’allait pas dégrader l’expérience utilisateur, nous avons déployé le sandbox progressivement en production. Les retours que nous avons reçus en interne comme en externe nous ont donné la confiance nécessaire pour livrer la fonctionnalité. Nous voyons maintenant un tiers des requêtes sur les plateformes prises en charge s’exécuter avec le sandbox, et nous avons intégré de nombreux clients Enterprise tels que NVIDIA.
À mesure que les agents passent de la génération de code à l’exploitation de systèmes de production, il devient primordial de fournir des limites d’exécution. Notre implémentation actuelle est un pas dans cette direction. À l’avenir, nous sommes particulièrement enthousiastes à propos d’agents natifs du sandbox, entraînés sur les contraintes de leur environnement. Ces agents peuvent se voir confier la liberté d’écrire directement des scripts et des programmes, plutôt que d’être limités à l’appel d’outils.
Si vous êtes intéressé par le travail sur des problèmes techniques de fond liés au futur du développement logiciel, contactez-nous à hiring@cursor.com.