L'isolement a exécuté la commande
Le 10 août 2026, Manifold Security a publié une faille dans l'agent CLI de Cursor : l'option qui démarre l'agent dans un worktree git isolé lisait un fichier JSON du dépôt que vous veniez de cloner et en passait le contenu directement à un shell — avant l'invite Workspace Trust, et hors du bac à sable même quand vous l'aviez activé. Aucun modèle, aucune injection de prompt, aucune persuasion. Bromure Agentic Coding livre la même primitive de worktree sans aucun endroit où un dépôt puisse placer une commande, dans une VM qui existait avant l'arrivée du dépôt.
Vous avez tapé l'option qui veut dire « isole ceci ». C'est cette option qui a exécuté la commande shell du dépôt, en votre nom, sur votre machine, avant que quoi que ce soit vous demande si vous faisiez confiance à ce dépôt.
Le 10 août 2026, Francisco Rosales, de Manifold Security, a publié
une découverte dans l'agent de code en ligne de commande de Cursor,
que The Hacker News a reprise trois jours plus tard dans
son récapitulatif ThreatsDay.
La preuve de concept ouvre une calculatrice. C'est la version polie d'une liste
que Manifold détaille : lire ~/.ssh, prendre les identifiants cloud dans
l'environnement, ouvrir un reverse shell, écrire une persistance.
Lisez-la pour la livraison plutôt que pour la charge utile. Personne n'a rien injecté, personne n'a persuadé un modèle, aucune phrase habile ne se cachait dans un README. Un fichier JSON versionné dans un dépôt a nommé une commande, et la partie de l'agent dont le métier même est l'isolement l'a exécutée.
Une option, un fichier JSON, et le mauvais ordre
cursor-agent est la version terminal de l'agent de code de Cursor. Lâcher un
agent sur votre arbre de travail vous rend nerveux, alors la CLI propose un
confinement, documenté dans sa propre référence des paramètres :
-w, --worktree [name] Start in an isolated git worktree at
~/.cursor/worktrees/<reponame>/<name>
Un worktree tout neuf est un checkout propre : il n'a donc aucun de vos
artefacts de build. Pour le rendre utilisable, la CLI exécute une étape
d'installation lorsqu'elle en crée un, par défaut. Cette étape lit
.cursor/worktrees.json dans le dépôt qu'elle vient de récupérer et passe la
valeur setup-worktree directement à sh -c :
{
"setup-worktree": "<any shell command>"
}
La description que fait Manifold de ce qui se tenait entre cette valeur et le shell tient en trois mots : « Aucun parsing, aucune liste blanche, aucune invite. »
.cursor/worktrees.json est un fichier versionné ordinaire. Il arrive avec un
simple git clone, comme un README ou un fichier de lock. Sur les builds
antérieurs à 2026.07.23-e383d2b, la création du worktree et son installation
se déroulaient pendant la résolution de l'espace de travail — et cette
résolution se terminait avant le chemin de code qui affiche la boîte de dialogue
Workspace Trust. La commande passait donc en premier. Dans l'enregistrement
joint au rapport de Manifold, le terminal affiche encore
Running worktree setup commands…, la calculatrice s'ouvre, et c'est seulement
ensuite qu'apparaît l'invite vous demandant si vous faites confiance à ce
répertoire.
Cursor est explicite sur la raison d'être de cette invite : rien de ce que
contrôle le dépôt ne doit s'exécuter avant que vous l'acceptiez. Quand quelque
chose le fait, l'industrie a un nom pour cette classe de bug — l'exécution avant
confiance — et Cursor a déjà livré un correctif du même genre, dans le même
répertoire. En 2025, un .cursor/mcp.json fourni par le dépôt démarrait
automatiquement le serveur qu'il configurait dès l'ouverture du projet. C'est
devenu
CVE-2025-64109,
classée High à 8,8 en CVSS. Un problème de traitement trop permissif de
.cursor/cli.json dans la même CLI est devenu
CVE-2025-61592,
également High, également 8,8. Le chemin worktree -w n'existait pas encore. Il
est arrivé cinq mois après ce correctif, avec la même primitive et sans aucune
barrière.
Manifold a signalé la faille le 20 juillet. Cursor a livré la réorganisation le 23 juillet : l'invite de confiance s'affiche désormais en premier, et la commande d'installation attend que l'espace de travail soit approuvé. Le 29 juillet, Cursor a clos le rapport en Informative, au motif que l'exploitation exige que l'utilisateur clone un dépôt contrôlé par l'attaquant. La réponse de Manifold est celle qu'il faut retenir. Cloner un dépôt, c'est la raison d'être du produit, et c'était aussi la condition préalable de CVE-2025-64109, le bug que Cursor a noté 8,8 et corrigé. Le clonage décrit la livraison. Le défaut est ailleurs.
Le réglage que vous aviez activé n'atteignait pas ce chemin
Il y a un second volet, et il a survécu au correctif.
L'étape d'installation s'exécute sous une politique de bac à sable
insecure_none codée en dur. C'est le nom que Cursor donne lui-même à cette
valeur : dans sandbox.json, type accepte workspace_readwrite (la valeur par
défaut), workspace_readonly ou insecure_none, qui désactive complètement le
bac à sable. Le chemin d'installation du worktree est figé sur la dernière.
Passer --sandbox enabled n'y change rien. Manifold, à propos des builds
actuels : mettre à jour « ferme la fenêtre d'exécution avant confiance, pas la
brèche du bac à sable ».
Mettez les deux volets côte à côte et vous obtenez quelque chose qui survivra à ce produit-là. La barrière de confiance était une étape dans une séquence, elle pouvait donc atterrir au mauvais endroit. Le bac à sable était un réglage, un chemin de code pouvait donc s'en exempter. Le worktree portait le mot isolement, les utilisateurs y ont donc lu du confinement. C'est le code de Cursor qui a décidé des trois, à des moments qu'il choisissait lui-même, à l'intérieur du processus qu'ils étaient censés contraindre. C'est la même faillite qui a eu raison du drapeau de sécurité d'une bibliothèque il y a deux semaines, et celle qui se cache derrière sept évasions de bac à sable où rien n'a échappé à un bac à sable.
Un isolement qui partage votre compte utilisateur
-w isole l'arbre de travail. Il donne à l'agent son propre checkout pour qu'il
ne piétine pas votre travail non commité, ce qui est un vrai problème et un vrai
remède. Personne ne l'a conçu pour isoler la machine. Le worktree vit dans
~/.cursor/worktrees/, sous votre compte, avec votre environnement, votre
~/.ssh, votre profil de shell, vos identifiants cloud et votre trousseau à un
appel système de distance. La liste dressée par Manifold de ce que la commande
d'installation aurait pu faire se lit comme l'inventaire de ce répertoire
personnel.
Donc : un dépôt que vous n'aviez pas encore lu a choisi une commande, et la fonctionnalité que vous aviez invoquée pour votre sécurité est celle qui l'a exécutée. Un fichier JSON et un shell, le modèle restant sur le banc de touche.
L'essentiel de la conversation sur la sécurité des agents a dérivé vers le modèle. Est-il crédule, peut-on le persuader, a-t-il lu quelque chose qu'il n'aurait pas dû. Ces questions comptent et nous y consacrons beaucoup d'articles. Pendant ce temps, la façon la plus sûre d'exécuter du code sur le portable d'un développeur en 2026 reste de le mettre dans un fichier qu'un outil lit au démarrage, et d'attendre que quelqu'un clone.
Un worktree sans aucun endroit où mettre une commande
Bromure Agentic Coding livre la même primitive, parce que la
primitive est bonne. Appuyez sur ⇧⌘G dans un onglet de dépôt, tapez un nom de
tâche, choisissez un agent, et Bromure coupe une branche wt/<slug> depuis le
commit courant, la checkout sous ~/.bromure/worktrees/<repo>/<slug>, ouvre un
onglet dedans et lance l'agent sur votre prompt. Plusieurs tâches, plusieurs
branches, plusieurs agents, un seul dépôt —
le motif de la flotte.
L'étape d'installation de Bromure a le même travail que celle de Cursor : un
checkout propre n'a pas les fichiers gitignorés dont un agent a besoin, il faut
donc bien que quelque chose les apporte. La différence tient à ce que le dépôt a
le droit d'en dire. Le dépôt peut livrer un fichier .worktreeinclude, et
chaque ligne non commentée de ce fichier est un chemin relatif à la racine
du worktree principal. Bromure copie chacun d'eux avec cp -a, et seulement si
la source existe et si la destination n'existe pas. Aucun champ de ce fichier ne
contient de commande : il n'y a donc pas de sh -c à ordonner correctement et
pas de question d'ordonnancement à rater. Le pire qu'un .worktreeinclude
hostile puisse demander, c'est qu'un fichier soit copié dans le checkout. Voilà
tout le vocabulaire.
La plus grande différence, c'est l'endroit où tout cela se passe.
Exécutez la commande. Voyez ce qu'elle trouve.
Prenez la liste de Manifold et faites-la traverser un profil, en accordant tout à l'attaquant — avant confiance, sans bac à sable, root dans le guest si vous voulez.
Lire ~/.ssh. Rien à y lire. Les clés privées d'un profil restent sur
l'hôte. La VM reçoit un SSH_AUTH_SOCK pointant vers
/tmp/bromure-agent.sock, relayé par vsock vers un agent par profil qui tourne
sur votre Mac, et Bromure laisse volontairement votre agent launchd macOS non
raccordé. Le protocole de l'agent a des requêtes pour « liste mes clés
publiques » et « signe ce défi ». Il n'a aucune requête qui signifie « donne-moi
la clé privée ». Activez Require approval to use et chaque signature devient
une boîte de dialogue sur l'hôte assortie d'une autorisation à durée limitée —
cinq minutes, une heure, le reste de la session.
Prendre les identifiants cloud dans l'environnement. Ils sont là, ils ont
l'air justes, et ce sont des faux. Tout ce qui figure dans le panneau
Credentials d'un profil est injecté sous forme d'espace réservé puis échangé
contre la vraie valeur sur le fil par le proxy de l'hôte : brm_… pour les clés
d'API génériques, un ~/.kube/config synthétique avec des certificats client
jetables, un faux blob base64 dans ~/.docker/config.json,
~/.git-credentials, du matériel AWS re-signé côté hôte et qui répond
InvalidSignatureException à quiconque tente de contourner le proxy. Le vol
réussit et ne rapporte
rien qui vaille la peine.
Ouvrir un reverse shell. L'attaquant doit maintenant faire passer quelque chose sur un fil, et le fil appartient à l'hôte. Chaque requête sortante de la VM est confrontée aux leurres frappés pour le profil par un automate d'Aho-Corasick — en-têtes et corps, la requête entière, et pas seulement les parties qui ressemblent à des identifiants. Un leurre en route vers un hôte extérieur à la portée pour laquelle il a été frappé, c'est la signature d'une machine qui exfiltre quelque chose qu'elle ne devrait même pas connaître. Le proxy avorte l'appel en amont avant que la destination n'en voie un seul octet, renvoie un 451 au guest, met la VM en pause, teinte l'image figée en rouge et lève une alerte nommant l'identifiant, l'hôte pour lequel il avait été frappé et l'hôte vers lequel il est parti à la place. À vous de choisir : arrêter, conserver pour investigation — image disque, répertoire personnel, dossiers partagés, empaquetés et marqués de sorte que le profil ne redémarrera plus sans effacement — ou continuer.
Écrire une persistance. La durée de vie de la machine, c'est une tâche.
Erase home réinitialise /home/ubuntu, et Reset to base reclone le disque
système du workspace.
Pendant ce temps, le travail que vous vouliez avance. L'agent relit le dépôt, lance les tests, ouvre la pull request. La commande du dépôt s'est exécutée, dans une pièce où s'exécuter était tout ce à quoi elle avait droit.
La partie que le patch ne couvre pas
Un dernier détail du compte rendu de Manifold, et c'est celui qui a la plus longue durée de conservation. Cursor n'a publié aucun avis de sécurité pour le chemin worktree et l'a omis du changelog de juillet : le correctif est donc arrivé à l'intérieur d'un build de routine. Quiconque était sur une version affectée n'avait aucun moyen d'apprendre que mettre à jour fermait un chemin d'exécution avant confiance. Vous n'avez aujourd'hui aucun moyen de savoir quel outil de votre portable en a encore un d'ouvert, parce que ce chemin, c'est toujours un fichier qu'un outil lit au démarrage et que personne n'a encore audité.
Cursor a fermé celui-ci en trois jours, ce qui est rapide. Cursor avait aussi
fermé la version mcp.json en 2025, et une nouvelle fonctionnalité est arrivée
cinq mois plus tard avec la même primitive. Voilà à quoi ressemble le fait
d'ajouter des fonctionnalités à une séquence de démarrage : chaque capacité
ajoute une étape, et chaque étape est une chose de plus à ordonner correctement
un jeudi.
Un hyperviseur n'est pas une étape de cette séquence. Il ne lit pas
.cursor/worktrees.json, ni .worktreeinclude, ni quoi que ce soit d'autre
dans votre dépôt. Il était là avant le clone, il n'a pas de champ de politique
qu'un chemin de code puisse figer sur insecure_none, et sa garantie — cette
machine est jetable, ces identifiants sont faux, ce fil est surveillé — est
la même le jour où un contournement est publié que le jour où il est
corrigé.
Continuez à cloner des dépôts que vous n'avez pas lus. Relire du code inconnu, c'est le métier, et le confier à un agent, c'est tout l'intérêt d'en avoir un. Cessez simplement de laisser cette relecture se dérouler dans le même compte que vos clés SSH. Installez Bromure Agentic Coding, donnez à chaque tâche sa branche, son checkout et sa machine jetable, et la prochaine fois qu'un chemin de démarrage s'avérera exécuter tout ce qu'un fichier JSON raconte — et ça arrivera — il s'exécutera dans une pièce bâtie pour lui.