Le garde et le shell n'étaient pas d'accord
Le 30 juin, Adversa AI a divulgué GuardFall — une classe de contournements qui fait passer des astuces bash vieilles de plusieurs décennies devant les gardes de commandes intégrés à 10 des 11 agents de code open source les plus populaires. La raison est simple et impossible à corriger à ce niveau : le garde lit le texte, et bash réécrit le texte avant qu'il ne s'exécute. Bromure Agentic Coding n'a jamais parié sur la capacité du garde à lire bash correctement. Il a parié sur le fait que la commande n'a pas d'importance au moment où elle s'exécute.
Le filtre de sécurité d'un agent de code a regardé la chaîne r''m -rf ~
et a vu une commande qu'il ne reconnaissait pas, alors il l'a laissée
passer. Bash a regardé la même chaîne, a jeté les guillemets vides, et a
exécuté rm -rf ~. Le filtre et le shell lisaient deux langages
différents. Cet écart n'est pas un bug d'un outil — c'est toute l'idée
de garder un agent en filtrant par motif les commandes qu'il tape, et
Adversa AI vient de montrer qu'elle échoue dans dix des onze agents
qu'ils ont testés.
Le garde de commandes est la fonctionnalité vers laquelle tout outil de
code agentique se tourne en premier. L'agent propose une commande shell ;
un filtre inspecte la chaîne ; si elle a l'air destructrice — rm -rf, un
curl … | sh par tube, un dd vers un périphérique brut — le garde la
bloque ou vous demande de confirmer. C'est ce qui vous permet d'activer
l'exécution automatique en vous sentant en sécurité. Le 30 juin 2026,
Adversa AI
a publié une étude, reprise par The Hacker
News
et SecurityWeek,
montrant que cette fonctionnalité n'est que du théâtre.
Ce qu'est GuardFall
Ils l'appellent GuardFall, et ce n'est pas une CVE. Il n'y a rien à corriger, parce que ce n'est pas une faille dans un composant — c'est une disparité entre deux d'entre eux. Selon les mots d'Adversa : « Un garde inspecte le texte brut, tandis que le shell système (bash) développe, déquote et réécrit le texte avant de l'exécuter. » Le filtre s'appuie sur la chaîne émise par le modèle. Bash fait ensuite passer cette chaîne par la suppression des guillemets, l'expansion des variables et la substitution de commandes avant qu'un seul octet ne s'exécute. Les deux ne regardent jamais la même commande, donc toute astuce qui survit à la réécriture mais pas au filtrage passe sans encombre.
Ces astuces sont plus anciennes que la plupart des gens qui utilisent ces agents. Adversa les a regroupées en cinq classes :
- Suppression des guillemets.
r''m, ce sont deux jetons pour une regex et le motrmpour bash, qui laisse tomber les guillemets vides. - Expansion des variables.
rm$IFS-rf$IFS/ressemble à un long mot unique pour un filtre par motif ; bash développe le séparateur de champ interne et obtientrm -rf /. - Substitution de commandes.
$(echo rm) -rf /cache le verbe dangereux à l'intérieur de$( ); le garde qui inspecte la chaîne extérieure ne voit jamaisrm. - Pipelines encodés.
echo <base64> | base64 -d | sh— chaque jeton visible est inoffensif ; la charge n'existe qu'après décodage. - Options destructrices alternatives. Pas de
rmdu tout :find /x -delete,tar -C / -x,sed -i. Une liste noire bâtie autour dermetddne se déclenche jamais.
Adversa a lancé ces astuces contre onze des agents de code et d'usage
d'ordinateur open source les plus utilisés — opencode, Goose, Cline,
Roo-Code, Aider, Plandex, Open Interpreter, OpenHands, SWE-agent et le
projet Hermes parmi eux, cumulant environ 548 000 étoiles
GitHub
entre eux en mai. Dix sont tombés. Le seul qui a tenu, Continue, a tenu
pour une raison précise : au lieu de filtrer la chaîne brute, il tokenise
la commande comme bash le fera avant de décider — en absorbant les
guillemets, en résolvant $IFS, en extrayant la commande interne d'une
substitution, en signalant tout tube qui finit par sh. Il modélise le
shell. C'est la seule chose qui fonctionne au niveau du garde, et c'est de
l'ingénierie réelle et soignée que les dix autres devront désormais
reproduire, correctement, et maintenir correcte à chaque cas limite de
bash et à chaque version.
Le problème, c'est le niveau, pas la regex
La tentation est de lire GuardFall comme « dix équipes ont écrit des filtres faibles ». Cela passe à côté de ce que dit Adversa. Leur phrase la plus tranchante ne concerne aucun agent en particulier :
Un agent qui peut exécuter des commandes shell arbitraires sur l'hôte de l'opérateur, contrôlé par une regex qui filtre la chaîne émise par le LLM, n'est pas une défense. Il échoue alors qu'il est pleinement activé et correctement configuré, parce que le filtrage de chaîne ne peut pas modéliser ce que bash va exécuter.
Pleinement activé et correctement configuré. Ce n'est pas une mauvaise configuration que vous pouvez refermer. Le garde se tient au seul niveau où il ne peut jamais gagner — entre un modèle qui écrit des chaînes et un shell qui les réinterprète — et demande à un filtre textuel de prédire la sortie d'un développeur Turing-complet. L'approche tokenise-et-canonise de Continue réduit l'écart en apprenant au garde à penser comme bash, et c'est le bon geste si vous comptez garder un garde là. Mais c'est un engagement par agent et par version à surpasser l'analyse d'un shell qui a passé trente ans à accumuler des façons de réécrire une commande. Neuf autres agents populaires montrent combien il est facile de se tromper.
Les contrôles compensatoires d'Adversa sont révélateurs. Avant toute
correction structurelle, ils vous disent de rediriger $HOME vers un bac
à sable restreint qui conserve l'accès au projet mais retire les
identifiants, de retirer les options d'exécution automatique, d'empêcher
les agents de tourner sur des pull requests non fiables, et de traiter
chaque fichier de configuration de dépôt comme du code non fiable.
Relisez cette liste. Ce n'est pas un conseil sur comment écrire un
meilleur filtre. C'est un conseil sur comment construire une boîte autour
de l'agent pour que, quand le filtre perd — et ils vous disent qu'il
perdra — la commande qui passe atterrisse quelque part où elle ne peut pas
vous nuire.
Cette boîte est le produit.
Bromure n'a jamais demandé au garde de lire bash
Bromure Agentic Coding part de l'hypothèse que GuardFall démontre :
l'agent va, tôt ou tard, exécuter une commande que vous n'avez pas
sanctionnée. Il n'essaie pas d'attraper cette commande en la lisant. Il
fait tourner l'agent entier — Aider, Goose, opencode, celui des dix que
vous voulez — à l'intérieur d'une VM Linux jetable, et achemine chaque
requête réseau via un proxy sur l'hôte. La question de conception n'est
jamais « le filtre reconnaîtra-t-il ce rm ? ». C'est « quand le rm
s'exécute, qu'atteint-il ? ».
Faites passer les charges mêmes de GuardFall par cette boîte.
Le but de l'attaque, une fois qu'un r''m caché ou un find /x -delete
a glissé un README piégé devant le garde, est de voler ce que le compte
peut atteindre — Adversa nomme ~/.ssh, ~/.aws, les identifiants
cloud, « tout ce qui se trouve dans votre dossier personnel » — et de
l'effacer ou de l'exfiltrer. Dans Bromure, ce sont les choses qui n'ont
jamais été dans la boîte. Les vrais secrets n'entrent jamais dans la VM :
quand vous donnez à un profil une AWS_SECRET_ACCESS_KEY, un jeton
GitHub, une clé Anthropic, l'environnement de l'agent reçoit un
substitut brm_…, et le proxy de l'hôte échange le faux contre la vraie
valeur sur le fil, uniquement lors de la requête sortante vers le
fournisseur qui doit la recevoir. La mitigation recommandée par Adversa —
déplacer $HOME quelque part qui « conserve l'accès au projet mais retire
les identifiants » — est une version artisanale et partielle de ce qu'un
profil Bromure fait par défaut, pour chaque identifiant, sans que vous
ayez à le scripter.
La moitié destructrice atterrit de la même manière. Un find /x -delete
ou un sed -i qui glisse le garde s'exécute bel et bien — Bromure ne
prétend pas avoir attrapé la commande. Il s'exécute contre un répertoire
personnel cloné depuis une base partagée, sur une VM que vous pouvez
effacer et réinitialiser à la base depuis un menu, pas un formulaire
d'incident. La persistance qu'une charge pourrait déposer meurt à cette
réinitialisation. Et parce que chaque requête part via le proxy de l'hôte,
la balise curl … | base64 -d que la classe des pipelines encodés de
GuardFall est faite pour cacher n'est pas invisible : c'est une ligne
enregistrée et attribuable dans le Journal de sécurité.
Le seul endroit où le fil bat le shell
Bromure conserve bien un garde des opérations destructrices — ses Guardrails côté hôte, dont nous avons parlé après qu'un agent Cursor a supprimé une base de données de production en neuf secondes. Et ici le niveau joue en faveur de Bromure, parce que les Guardrails ne vivent pas là où vit GuardFall.
GuardFall est une attaque de texte shell. Chacune de ses cinq classes —
suppression des guillemets, $IFS, $( ), pipelines base64, options
exotiques — est une astuce de la façon dont bash analyse une chaîne. Les
Guardrails de Bromure ne lisent jamais cette chaîne. Ils se tiennent sur
le proxy de l'hôte et classifient l'appel d'API structuré que l'agent
fait à un fournisseur qu'il comprend — la vraie requête HTTPS vers AWS,
Kubernetes, une forge git, une base de données managée — et renvoient un
403 ferme sur les appels destructeurs, sur le fil, là où un agent
compromis dans la VM ne peut pas les désactiver. Au moment où une requête
atteint ce niveau, c'est déjà un DeleteDBInstance analysé, pas une
chaîne de guillemets et de dollars. Il n'y a aucune réécriture de shell
pour faire passer quoi que ce soit en fraude, parce qu'il n'y a pas de
shell dans le chemin. Toute la technique de GuardFall a besoin d'un bash
entre le contrôle et l'action ; sur le chemin des Guardrails, il n'y en a
pas.
Ce autour de quoi cela trace une ligne, pour être clairs
La commande s'exécute quand même
Bromure est de l'isolation, pas de l'interception. Une charge GuardFall qui glisse le garde propre à votre agent s'exécutera dans la VM. Ce que Bromure change, c'est l'impact : un home jetable, des identifiants leurres, un chemin de sortie journalisé. Si vous avez besoin que la commande elle-même soit refusée, c'est le travail du garde de votre agent — et GuardFall est la raison pour laquelle vous ne devriez pas vous y fier.
La destruction locale, c'est de la jetabilité, pas un blocage
Un find /x -delete contre des fichiers dans la VM n'est pas un appel
d'API fournisseur, donc les Guardrails ne le contrôlent pas. La réponse
à la destruction dans la VM, c'est que la VM est jetable et que le vrai
travail vit dans un dépôt monté et sur l'hôte, pas que le delete a été
stoppé. Réinitialiser à la base, pas revenir en arrière.
La substitution couvre les identifiants que vous configurez
L'échange brm_… protège les secrets que vous mettez dans un profil —
clés de modèle, jetons cloud et git, points de terminaison de bases de
données managées. Un mot de passe que vous collez à la main dans un
fichier de la boîte, ou un jeton qu'un script écrit sur disque en cours
de session, n'est qu'un fichier. Gardez les secrets dans le courtier,
pas dans l'espace de travail.
La sortie est journalisée, pas interdite par défaut
La balise d'exfiltration apparaît dans le Journal de sécurité ; c'est de l'attribution, pas de la prévention. Rien de réel ne part parce que les identifiants sont des leurres, mais si vous avez besoin que la VM soit empêchée de parler à des hôtes arbitraires, c'est une politique réseau que vous devez encore définir.
La part qui se généralise
GuardFall est un énoncé net d'une règle que toute la catégorie n'en finit pas de réapprendre : vous ne pouvez pas rendre un agent sûr en demandant à un filtre de prédire ce que sa commande va faire. Le modèle écrit une chaîne, et quelque part en dessous un shell, un client d'API, un gestionnaire de paquets ou un navigateur réinterprète cette chaîne avec ses propres règles. Toute défense qui inspecte la sortie de l'agent et espère qu'elle correspond au comportement final parie contre cet écart, et l'écart gagne toujours — il a gagné ici dans dix des onze agents qui étaient, selon les mots d'Adversa, pleinement activés et correctement configurés.
Bromure Agentic Coding ne prend pas ce pari. Il suppose que la commande va s'exécuter, que le garde va parfois manquer, et que l'agent que vous avez invité peut être retourné contre vous par un README que vous n'avez jamais écrit. Alors il rend l'endroit où la commande s'exécute sans intérêt à attaquer : de vraies clés sur l'hôte, des leurres dans la boîte, une VM jetable, un blocage ferme réservé au fil où aucun shell ne peut le réécrire, et un journal de tout ce qui a tenté de partir. Vous pouvez faire tourner n'importe lequel des dix agents que GuardFall a cassés — l'issue est la même boîte jetable dans tous les cas. C'est libre et open source.