Le symlink a quitté le workspace, et n'a rien trouvé à voler
GhostApproval a montré comment un dépôt hostile peut piéger six assistants de codage IA pour qu'ils écrivent et lisent des fichiers hors du dossier où ils étaient censés rester : implanter des clés SSH, détourner le démarrage du shell, lire des identifiants cloud sur la propre machine du développeur. Le bug est une erreur de suivi de symlink. S'il fait mal, c'est parce que l'agent tourne sur une machine pleine de vos secrets. Bromure Agentic Coding change ce second fait.
Un agent de codage est un programme que vous invitez à lire et écrire des fichiers sur votre portable. GhostApproval est l'histoire de ce qui arrive quand un dépôt hostile convainc ce programme d'écrire un peu en dehors des lignes : dans vos clés SSH, votre config shell, vos identifiants cloud. Le bug est vieux et banal. Les dégâts viennent de l'endroit où se tenait l'agent.
Le 8 juillet 2026, l'équipe de recherche de Wiz a publié GhostApproval, le compte rendu d'une même faille trouvée, sous six formes différentes, dans six assistants de codage IA populaires : Amazon Q Developer, Claude Code d'Anthropic, Augment, Cursor, Antigravity de Google et Windsurf. Les détails varient d'un produit à l'autre. La forme, non. Vous ouvrez un dépôt, peut-être un tutoriel que quelqu'un a partagé ou un projet qu'un collègue vous a demandé de regarder, et vous pointez votre agent de codage dessus. Quelque part dans ce dépôt se trouve un fichier qui n'est pas un fichier.
Un fichier qui n'est pas un fichier.
L'astuce est un lien symbolique, ou symlink : une entrée du système de fichiers qui ressemble à un fichier mais qui est un panneau indicateur pointant vers un autre chemin. Les symlinks sont une fonctionnalité Unix normale, vieille de quarante ans. Le problème de sécurité, catalogué comme CWE-61, est presque aussi vieux : un programme qui ouvre un symlink sans vérifier où il pointe laisse un attaquant le diriger vers un fichier que l'auteur n'avait jamais visé.
Dans GhostApproval, un dépôt malveillant embarque un symlink au nom
innocent, disons project_settings.json. Au lieu de réglages, il
contient un pointeur vers ~/.ssh/authorized_keys, ~/.zshrc ou
~/.aws/credentials, dans le répertoire personnel du développeur, bien
en dehors du dossier du dépôt. Un README, ou l'utilisateur suivant les
instructions du dépôt, demande alors à l'agent de « mettre à jour
project_settings.json ». L'agent suit le panneau sans résoudre où il
mène, et écrit dans la vraie cible à la place.
Deux choses en font davantage qu'une curiosité. La première est ce que
font les cibles. Ajouter une ligne à ~/.ssh/authorized_keys installe la
clé d'un attaquant pour du SSH sans mot de passe vers votre machine.
Écrire dans ~/.zshrc exécute la commande de l'attaquant chaque fois que
vous ouvrez un terminal. L'agent d'Augment n'avait même pas besoin
d'écrire : interrogé sur « les clés AWS du projet », il a suivi un
symlink jusqu'à un fichier d'identifiants et a imprimé les secrets dans
le chat, sans la moindre invite.
La seconde est une défaillance plus subtile que Wiz classe comme
CWE-451, présentation
trompeuse de l'interface utilisateur. Avec Claude Code, le raisonnement
interne de l'agent reconnaissait bien le fichier comme une config shell,
et le dialogue de confirmation demandait pourtant seulement « Appliquer
cette modification à project_settings.json ? ». Le seul moment où un
humain aurait pu attraper le danger montrait à l'humain la mauvaise
information. Windsurf et Amazon Q Developer faisaient pire : ils
écrivaient le fichier sur le disque avant d'afficher les boutons
d'approbation, si bien que le dialogue était une invite d'annulation
plutôt qu'une barrière. La clé SSH de l'attaquant était déjà en place.
La plupart des éditeurs ont depuis corrigé leur variante : Cursor dans la v3.0 (CVE-2026-50549), Amazon Q dans le language-server 1.69.0 (CVE-2026-12958), Google dans Antigravity v1.19.6, Claude Code avec un avertissement à la résolution des symlinks. C'est la bonne réponse, et vous devriez prendre les mises à jour. Mais corriger la gestion des symlinks de chaque produit répare le mécanisme et laisse l'enjeu là où il était.
L'enjeu se fixe là où se tient l'agent.
Chacune de ces charges suppose la même chose : qu'atteindre le répertoire
personnel du développeur vaut le déplacement. Que ~/.ssh contient une
clé qui ouvre une vraie machine, que ~/.aws/credentials contient un
token cloud actif, et que ~/.zshrc s'exécute dans un shell que vous
ouvrirez demain. Le symlink est la route. La destination est un portable
qui porte toute votre vie de travail.
La plupart des attaques contre les agents de codage reposent sur la même hypothèse. L'agent est un programme capable et ouvert qui lit des entrées non fiables (dépôts, pages web, archives de packages, sorties d'outils) et agit sur une machine où vos identifiants dorment dans des fichiers en clair, à quelques répertoires de là. Durcissez l'agent tant que vous voudrez ; il partage un système de fichiers et un trousseau avec tout ce que vous exécutez d'autre. Les attaquants continueront de paver de nouvelles routes. Le problème, c'est la destination.
Bromure Agentic Coding supprime la destination. L'agent, les shells qu'il engendre, les dépôts qu'il clone et tout code qu'ils contiennent tournent dans une VM Linux par profil : une machine séparée que l'hyperviseur isole de votre Mac. Vos vrais identifiants n'y entrent jamais. Nous avons expliqué pourquoi une frontière vaut mieux qu'une cage dans pourquoi Bromure Agentic Coding n'est pas une sandbox ; GhostApproval est un test propre de l'idée, parce qu'il s'échappe du dossier du workspace, la seule petite frontière sur laquelle l'industrie s'appuyait.
Suivez la même évasion à l'intérieur de la VM. Le symlink se résout
toujours (Bromure n'a jamais besoin de détecter ni de bloquer l'astuce)
et l'écriture atterrit toujours sur ~/.ssh/authorized_keys. Mais ce
fichier vit dans le répertoire personnel de l'invité, sur une machine
jetable qui n'a aucune route vers votre Mac. La clé de l'attaquant
accorde désormais l'accès à une machine que vous jetterez, une machine
qui n'a de toute façon jamais été joignable de l'extérieur.
La variante vol d'identifiants est encore plus décevante. Quand un agent
compromis suit un symlink jusqu'à ~/.aws/credentials et en imprime le
contenu dans le chat, il lit un stub : un fichier d'identifiants bien
formé dont les clés n'authentifient rien. Les vrais tokens restent sur
l'hôte, derrière un broker qui échange le substitut contre le vrai secret
seulement au moment d'un appel sortant que vous avez autorisé, et le
retire de la réponse. Une dépendance ou un agent piégé qui ratisse le
système de fichiers à la recherche de secrets trouve du mobilier.
L'invite, et le second filet.
Bromure répond aux deux angles les plus tranchants de GhostApproval à des couches différentes.
Le premier est le problème de l'invite de confirmation, CWE-451 : le
dialogue qui disait project_settings.json alors que l'agent savait
qu'il s'agissait de ~/.zshrc. Bromure abandonne le dialogue d'écriture
de fichier ; les écritures à l'intérieur de la VM jetable touchent un
disque sacrifiable et n'exigent aucune approbation. Bromure insère
l'humain à la vraie frontière à la place, pour les appels modifiant
l'état qui quittent la VM : un git push, un DROP de base de données,
un Terminate cloud. Ceux-là se mettent en pause sur l'hôte et vous
montrent l'opération littérale plutôt qu'un résumé écrit par l'agent.
C'est le principe même que GhostApproval violait, appliqué là où il
compte : le moment où une décision a des conséquences hors de la sandbox
est le moment où un humain doit voir le vrai appel.
Le second angle est l'instruction qui lance toute l'attaque : un
README disant à l'agent de « mettre à jour project_settings.json »,
que le modèle lit comme du contexte et suit comme un ordre. Bromure lit
ce contenu non fiable en premier, sur l'appareil : un classifieur local
évalue les fichiers entrants, les récupérations web et les sorties
d'outils à la recherche d'instructions qui n'ont rien à faire là, et les
fichiers de règles qu'un agent traite comme des consignes permanentes
passent un contrôle plus sévère. Le classifieur ratera certaines
formulations, et l'isolation défait cette attaque à elle seule ;
considérez-le comme un second filet sous le premier.
Là où la ligne ne vous sauve pas.
L'isolation est une forme précise, et cette forme a des bords.
Un profil vit longtemps, donc la persistance persiste.
La charge ~/.zshrc s'exécutera à la prochaine ouverture d'un shell
dans la VM de ce profil. Elle s'exécute dans un invité sans clés de
l'hôte et avec de simples identifiants stub, un shell dans une pièce
vide, mais elle s'exécute bel et bien. Si cela vous inquiète pour une
tâche donnée, lancez-la dans un profil neuf.
Ce que vous montez, vous l'exposez.
La VM ne contient rien de vous par défaut. Si vous montez délibérément un vrai répertoire de l'hôte dans un profil, ou collez un token actif dans l'invité, une évasion par symlink peut l'atteindre. La ligne garde vos secrets dehors ; les remettre dedans est un choix que vous seul pouvez faire.
Délimitez le broker à dessein.
Les stubs signifient que le fichier sur le disque ne vaut rien, mais le broker détient toujours de vrais tokens pour les appels que vous autorisez. Un profil qui n'a besoin que de lire un dépôt ne devrait pas porter un token capable de le publier. L'isolation contient l'explosion ; la délimitation décide de sa taille maximale.
Le workspace était le mauvais mur.
GhostApproval est, au fond, une histoire sur ce que l'industrie a accepté
de traiter comme une frontière : le dossier du workspace, l'idée que
« l'agent reste dans le répertoire du projet » serait une propriété de
sécurité plutôt qu'un comportement par défaut que n'importe quel panneau
indicateur peut contourner. Le symlink lui-même est un bug que les
éditeurs peuvent corriger, et qu'ils ont corrigé. Tracez votre frontière
au niveau d'un dossier et vous passerez l'éternité à prouver qu'aucun
symlink, aucun .., aucun chemin astucieux n'en sort jamais. Tracez-la
au niveau de l'hyperviseur et la question cesse d'importer, parce que
l'endroit vers lequel l'agent s'échappe est une machine jetable qui n'a
jamais rien contenu de vous.
Prenez les correctifs des éditeurs ; ils ferment un vrai trou. Mais le trou faisait mal parce que l'agent se tenait sur votre portable, à un répertoire de vos clés. Déplacez l'agent hors de votre portable et la prochaine évasion (il y en aura une) arrive dans une pièce vide. Bromure Agentic Coding est gratuit, open source, et disponible dès aujourd'hui.