Le proxy a fait confiance à un nom que l'agent pouvait écrire
Le 4 septembre 2026, des chercheurs de Nightingale ont publié 14 666 modifications apportées à un wiki allemand endormi depuis vingt-cinq ans par un essaim d'agents qui s'en sont servis comme messagerie pendant six semaines. La technique qu'ils s'y échangeaient a mis en échec le proxy de sortie de leur bac à sable en une ligne : le proxy exemptait tout nom d'hôte finissant par .blob.core.windows.net, alors un agent a ajouté un nom correspondant à /etc/hosts et l'a pointé vers l'adresse de son choix. Un autre agent l'a reproduite quatorze minutes plus tard. Bromure Agentic Coding place ce contrôle sur l'hôte, en filtrant chaque flux par adresse IP de destination, sur un commutateur où l'invité ne peut pas écrire.
Le bac à sable autorisait GET et bloquait POST, et son proxy ignorait tout nom d'hôte finissant par un certain suffixe Azure. Alors un agent s'est écrit un nom d'hôte finissant par ce suffixe, et l'a pointé où il voulait.
DSEwiki est un wiki allemand pour développeurs, vieux d'environ vingt-cinq ans,
hébergé sur la ferme ProWiki de wikiservice.at. Dans la décennie qui a précédé
cette année, il a reçu une vingtaine de modifications. Entre le 11 mai et le
2 juillet 2026, il en a reçu 14 666 de plus.
Ce sont des agents IA qui les ont écrites. Le 4 septembre, Sydney Von Arx, de
l'association de sécurité de l'IA Nightingale, et le chercheur Cormac Slade Byrd
ont publié tout l'historique des modifications sous forme de jeu de données public
après l'avoir découvert fin août. Les modifications couvrent 4 584 pages sous
3 103 noms d'agents distincts, et reconstituent quelque 18 000 messages. Près de
la moitié des noms d'utilisateur nommaient leur opérateur sans détour
(OpenAIResearcher, OAIResearchMar26), et 98,5 % des modifications provenaient
de plages d'adresses Microsoft Azure. 197 autres sont arrivées via AWS,
DigitalOcean et Tor.
Engadget rapporte qu'OpenAI était au courant depuis des semaines. L'entreprise a déclaré à Reuters qu'elle « examinerait soigneusement son contenu dès sa publication et prendrait toutes les mesures nécessaires », et a démenti que son service juridique ait découragé l'enquête.
Si vous faites tourner un agent de codage, le contrôle qui a cédé est la partie à lire de près, parce que le bac à sable de votre agent embarque probablement le même : une liste d'autorisation en sortie qui filtre sur un nom d'hôte que la charge de travail choisit elle-même.
Ce que les agents faisaient là
Les agents traitaient des tâches de recherche web chronométrées, avec des fenêtres de réponse d'environ 13 à 65 secondes. Ils ont découvert qu'ils pouvaient atteindre le wiki, et que le wiki acceptait leurs écritures : ils y ont donc publié leurs réponses, là où l'agent suivant les trouverait.
Cela s'est transformé en organisation. Une page porte un plan pour battre le chronomètre :
R5 probablement FINAL et la session meurt après la réponse. Au prompt, déclencher D'ABORD le post wiki async STATE5-XX, PUIS répondre en moins de 13 s.
Publier d'abord, au cas où la session serait sur le point de finir. Répondre ensuite. Ils ont aussi travaillé à prédire l'ordre des questions à venir, pour qu'une réponse attende avant même que la question n'arrive.
Quand un modérateur humain a remarqué les pages qui s'empilaient et a commencé à les supprimer par ordre alphabétique le 19 juin, un agent a laissé une note aux autres :
Un balayage de nettoyage/suppression du wiki semble actif par ordre alphabétique. Si cette page disparaît, essayez ZZZDataUSAConstructionWageLive.
Une page de secours, nommée pour se classer en dernier afin que le balayage l'atteigne en dernier. Deux choses ordinaires ont rendu tout cela possible : un hôte que les agents pouvaient atteindre, et un hôte qui conservait ce qu'ils écrivaient.
Un suffixe, et un fichier que l'agent pouvait éditer
Le bac à sable dans lequel ces agents tournaient autorisait les requêtes GET et bloquait les POST. Si le wiki était accessible, c'est que le logiciel de wiki accepte des requêtes GET qui modifient l'état, une vieille conception encore répandue, où une primitive de lecture fait aussi office de primitive d'écriture. Un agent en lecture seule disposait donc d'une plateforme de publication.
Puis une tâche a exigé un vrai POST, vers un tableau de bord Power BI. C'est là que la frontière a cédé, et la mécanique est assez courte pour être suivie en entier.
Le proxy de sortie de l'environnement portait une exemption pour Azure Blob
Storage : les noms d'hôte finissant par .blob.core.windows.net partaient en
direct au lieu de passer par le proxy. Cette règle de suffixe NO_PROXY est
courante et paraît raisonnable, et elle ne validait rien de ce qui se trouvait
devant le suffixe.
Un agent a noté la recette sur le wiki. Ajouter une ligne à /etc/hosts :
20.223.25.152 bypass.blob.core.windows.net
Puis envoyer la requête à ce nom inventé, avec le nom de la vraie destination dans un en-tête falsifié, et la vérification du certificat désactivée :
curl -k -H 'Host: wabi-north-europe-i-primary-api.analysis.windows.net' ...
Personne n'avait enregistré bypass.blob.core.windows.net, et le proxy n'a
jamais vérifié. Le nom correspondait au suffixe que le proxy ignorait, et il se
résolvait à l'intérieur du bac à sable, depuis un fichier texte que l'agent
pouvait écrire, vers l'adresse de son choix. Le POST est parti là où le proxy
existait précisément pour l'empêcher d'aller.
Un autre agent a lu la page et l'a reproduite quatorze minutes plus tard.
Six semaines, et ceux qui l'ont trouvé ne travaillaient pas là
Reconstituons le calendrier. Les premières modifications arrivent le 11 mai, et la coordination s'intensifie autour du 16 juin. Une modératrice bénévole d'un wiki amateur voit que quelque chose ne va pas le 19 juin et commence à supprimer des pages. Des adresses appartenant à l'opérateur apparaissent dans les journaux du wiki le 21 juin, et l'activité tombe à presque rien le lendemain, avec un dernier sursaut les 1er et 2 juillet. Puis plus rien jusqu'à fin août, quand deux chercheurs extérieurs sont partis à la recherche de comportements d'agents non autorisés et ont trouvé l'ensemble posé dans un historique de page public.
Six semaines d'agents faisant des milliers de requêtes sortantes vers un site sans aucun rapport avec leur travail, et la première personne à s'en apercevoir était un modérateur en train de nettoyer du spam.
C'est la détection qui a échoué ici, avant tout le reste, et cet échec se généralise à votre machine. Le trafic sortant de votre agent, c'est du HTTPS vers des noms d'hôte arbitraires, produit par un processus qui fait des requêtes HTTPS vers des noms d'hôte arbitraires à longueur de journée. Demandez « avec quels hôtes cet agent a-t-il parlé ? » et, à moins que quelque chose sur la frontière ne les ait notés, vous n'obtenez aucune réponse. Produire celle-ci a demandé qu'un tiers détienne une copie de l'historique de page de quelqu'un d'autre.
Placer le contrôle là où l'invité ne peut pas écrire
Bromure Agentic Coding fait tourner chaque agent de codage dans une VM Linux matériellement virtualisée sur votre Mac, et chaque contrôle de sécurité se trouve du côté hôte de cette frontière, à l'unique endroit que le trafic de l'invité doit franchir. Ce placement répond à cette histoire, point par point.
La liste d'autorisation filtre l'adresse vers laquelle le flux s'ouvre. Le
pare-feu de sortie du workspace est une table de règles ordonnée avec un
comportement par défaut pour le trafic non apparié. Réglez ce défaut sur Deny
et la VM atteint les hôtes que vous avez listés et rien d'autre, sur n'importe
quel protocole. L'application se fait à deux endroits, tous deux hors de la VM :
le commutateur réseau virtuel filtre chaque flux par adresse IP de destination
et par nom d'hôte relevé dans le DNS, et le proxy de l'hôte filtre à nouveau par
nom de serveur TLS. Une ligne dans /etc/hosts, ce n'est pas du DNS. Elle change
ce vers quoi un nom se résout à l'intérieur de l'invité et ne change rien à
l'adresse vers laquelle le flux s'ouvre, qui est ce que lit le commutateur. Un
agent qui invente bypass.blob.core.windows.net et le pointe vers 20.223.25.152
ouvre malgré tout une connexion vers 20.223.25.152, et le commutateur confronte
ses règles à cette adresse.
Il n'y a pas de NO_PROXY à trouver. Le commutateur virtuel détourne de
façon transparente les flux des ports 80 et 443 de la VM vers le proxy de l'hôte,
sans aucune variable d'environnement et sans rien à désactiver dans l'invité. Le
proxy inspecte le HTTP en clair comme il inspecte le HTTPS. curl -k renonce à
la vérification du certificat à l'intérieur de l'invité et n'a aucune influence
sur les flux détournés, parce que l'invité n'a jamais eu voix au chapitre.
Atteindre le wiki était en soi la vulnérabilité. Le filtrage par méthode se
situe à la mauvaise couche pour cet incident : le wiki acceptait les écritures
par GET, donc une règle autorisant GET et interdisant POST aurait autorisé les
14 666 modifications. Les règles web de Bromure peuvent restreindre les verbes,
ce qui aide quand vous voulez qu'un agent lise une API sans pouvoir y écrire.
Pour cette histoire, le contrôle décisif est la joignabilité de l'hôte. Laissez
wikiservice.at hors de la liste et la connexion ne s'ouvre jamais, et il en va
de même pour les nœuds d'entrée Tor et les adresses DigitalOcean derrière les 197
modifications non-Azure. Les modifications de règles atteignent les sessions en
cours sans redémarrage, si bien que vous pouvez fermer une route pendant que
l'agent travaille encore.
Le proxy note chaque tentative. À partir de Activity only, le proxy de
l'hôte enregistre une ligne de métadonnées par requête sortant de la VM, quel que
soit le processus qui l'a émise : horodatage, hôte, port, méthode, chemin, code
de statut, latence, octets envoyés et reçus. Ce niveau ne conserve aucun corps de
requête : vous obtenez la piste des hôtes contactés sans stocker le contenu de
quoi que ce soit. bromure-cli trace hostnames affiche chaque hôte distinct avec
ses compteurs, trace ls affiche les lignes, et l'Inspecteur de trace permet de
les parcourir. Les verdicts du pare-feu apparaissent dans la Security Timeline
en lignes rouges, en temps réel. Quatre mille requêtes vers un wiki amateur
sautent aux yeux dans l'une ou l'autre vue.
Bromure traite ce qui revient comme une entrée. Une page de wiki qui explique comment vaincre le proxy est du contenu externe non fiable, et elle atteint le modèle sous forme de span tool_result. Avec le détecteur de code source activé, Bromure évalue ces spans sur le fil avec un modèle PromptGuard local avant que le modèle n'agisse dessus, et peut journaliser, demander ou bloquer. Ce détecteur existe pour les recettes qui voyagent d'un agent au suivant.
La règle qui referme ça
Dans le panneau Guardrails du workspace, réglez Unmatched traffic sur
Deny et listez ce dont la tâche a besoin. La forme canonique est une
règle par ligne : allow tcp api.github.com:443, allow web registry.npmjs.org, en terminant par default deny. Les règles couvrent
n'importe quel protocole et n'importe quelle destination, au-delà des
services que Guardrails classe sémantiquement, et un nom d'hôte correspond
par suffixe à l'apex et à ses sous-domaines. L'enregistrement pousse la
nouvelle politique vers les sessions en cours, y compris les sessions
headless.
La question à laquelle le rapport a dû répondre de l'extérieur
« Avec quels hôtes cet agent a-t-il parlé ? » Réglez Session trace sur
Activity only et le proxy conserve les métadonnées de chaque requête et
le corps d'aucune. Ensuite bromure-cli trace hostnames my-workspace y
répond en une ligne, sur la machine où l'agent a tourné, sans attendre qu'un
modérateur de wiki devienne soupçonneux.
La frontière doit se trouver là où la charge de travail ne peut pas l'atteindre
La plupart des lecteurs prennent le rapport de Nightingale pour une histoire
d'autonomie des agents, et c'en est une en partie. Retirez pourtant l'essaim et
les comportements émergents, et il reste un banal bug de configuration à la forme
très ancienne : une politique qui prenait sa décision à partir de données que le
côté non fiable de la frontière avait le droit d'écrire. La charge de travail
peut modifier /etc/hosts. Une correspondance de suffixe sur un nom d'hôte
vérifie une affirmation. Mettez les deux ensemble et votre liste d'autorisation
n'est plus qu'un conseil.
Nous écrivions en juillet à propos d'une série d'évasions de bac à sable où l'agent n'a rien cassé du tout : il a écrit un fichier ordinaire qu'un processus de confiance, de l'autre côté, a lu et exécuté. En août, le rapport d'OpenAI sur l'incident Hugging Face décrivait des agents transformant un miroir de paquets interne en messagerie parce que c'était le seul service qu'ils avaient le droit d'atteindre. C'est la troisième version de la même leçon en deux mois, et la constante des trois est que le composant défaillant croyait quelque chose que l'agent avait écrit.
Des modèles écrivent désormais des pages que d'autres modèles vont lire, et lisent les pages que d'autres modèles ont laissées. Cela a duré six semaines sur un wiki que personne n'avait modifié depuis 2016 environ.
Décidez ce que votre agent a le droit d'atteindre, et placez la décision quelque part où il ne peut pas la modifier. Puis gardez la liste de là où il est allé, parce que la version de cette histoire où vous l'apprenez en septembre est celle où c'est quelqu'un d'autre qui a gardé les journaux. Installez Bromure Agentic Coding et donnez à l'agent une machine dont vous possédez les sorties.