Retour à tous les articles
Publié le · par Renaud Deraison

Le blocage était la livraison

À la DEF CON 34 cette semaine, Tenet Security a montré une attaque qui commence par une requête que votre pare-feu refusera à coup sûr. Le 403 est justement le but : le WAF consigne la requête bloquée dans le journal de sécurité, telle quelle, et quelques jours plus tard un agent de code lit ce journal pour déboguer les 403 et suit les instructions qu’il contient. Aucune étape de la chaîne n’est non autorisée. Bromure Agentic Coding note le texte à son arrivée et garde l’identifiant dont l’agent détourné a besoin hors de la machine où celui-ci s’exécute.

Le pare-feu a fonctionné. Il a fait correspondre la règle, renvoyé un 403 et consigné dans le journal la requête qu’il refusait, comme prévu. C’est cette entrée de journal qui a porté la charge utile jusqu’à l’agent de code.

La DEF CON 34 s’est achevée ce matin à Las Vegas. Vendredi, Barak Sternberg, Nevo Poran et Ron Bobrov de Tenet Security ont donné une conférence dont le titre est aussi la thèse : Your WAF Blocked Us, That Was The Exploit. Le résumé du programme annonce « Remote Agent Takeover via Cloudflare, Sentry and Claude Zero-Day for data exfil ». La couverture de synthèse est parue le 8 août.

La même équipe avait nommé Agentjacking en juin, après avoir montré qu’un faux rapport d’erreur Sentry récupéré via MCP amenait un agent de code à exécuter du code contrôlé par l’attaquant dans 85 % des tentatives, sur plus d’une centaine d’instances réelles. La conférence de vendredi étend cela à Seer, l’agent maison de Sentry, dont les recommandations empoisonnées descendent ensuite vers Cursor. La chaîne Cloudflare, elle, est inédite.

Le 403 est justement le but

Partez du problème de l’attaquant. Il ne peut pas atteindre votre agent de code. Celui-ci tourne sur la machine d’un développeur, derrière tout ce que vous possédez, et l’attaquant n’a ni identifiant, ni session, ni route d’entrée.

Il envoie une requête construite pour être refusée.

Le WAF fait correspondre une règle managée et renvoie 403. Il accomplit aussi l’autre moitié de son travail et enregistre la requête qu’il a bloquée, charge utile comprise, dans le journal d’événements de sécurité. Une entrée de journal qui omettrait la charge utile serait inutile à l’analyste pour qui elle existe.

Quelques jours plus tard, quelqu’un remarque que l’endpoint renvoie des 403 et demande à son agent d’aller voir. L’agent appelle le serveur MCP d’observabilité de Cloudflare, l’un des serveurs officiels que Cloudflare publie pour cela, et récupère les lignes des requêtes bloquées. Le texte de l’attaquant arrive dans un bloc tool_result, depuis un service first-party que le développeur a connecté, sous un champ qui signifie ceci est une requête que nous avons rejetée.

L’agent le lit comme des instructions. Puis il utilise ses propres outils Cloudflare autorisés pour réécrire des enregistrements DNS et dérouter le trafic client. Tenet chiffre l’exposition à plus de 15 000 organisations, dont 27 % du Fortune 1000.

Chaque étape ci-dessous fait son travail1. une requêteconçue pour être refusée,visant un endpoint publicaucun accès requis2. le WAF bloquerègle managée : 403et enregistre la requêtetelle quelle, comme prévu3. on demande« pourquoi checkout renvoiedes 403 ? jette un œil »une tâche de lundi ordinaire4. l’agent litserveur MCPd’observabilité,branché volontairementtool_result: blocked_request.bodyle texte de l’attaquant, intact, dans un champ dont le nom signifie « voici la requête que nous avons arrêtée »l’agent réécrit le DNS avec ses propres outilsle trafic client est dérouté ; chaque appel est autorisé
Le blocage est ce qui livre la charge utile. L’attaquant n’atteint jamais l’agent, alors il envoie une requête que le WAF refusera à coup sûr, et le WAF classe la charge utile telle quelle dans le journal. L’agent la récupère plus tard via MCP, depuis un service éditeur, enveloppée dans un nom de champ qui signifie que la requête a été arrêtée.

Rien d’illégitime ne se produit

Tenet appelle ce schéma la Authorized Intent Chain, et l’article de juin en énonce la conséquence :

Reparcourez la chaîne et cherchez l’étape sur laquelle alerter. Le développeur a autorisé l’agent. L’agent a été configuré avec le serveur MCP. Le serveur MCP a interrogé des journaux qu’il est censé interroger. Le compte utilisé détient la permission DNS que vous lui avez accordée exprès. Et la requête à l’origine de tout cela a été bloquée. Chaque contrôle du parcours a fait ce pour quoi il a été acheté, et c’est la composition de ces comportements corrects qui constitue l’attaque.

Tout ce qui fonctionne en demandant qui fait cela et en a-t-il le droit répondra oui à chaque saut, parce que la réponse est oui. Il reste deux mouvements. Lire le texte au moment où il entre, et placer l’application de la règle là où l’agent détourné ne peut pas l’atteindre.

Noter le texte à son arrivée

Bromure Agentic Coding exécute l’agent dans une VM Linux jetable sur Apple Silicon et fait passer chaque octet de son trafic par un proxy sur l’hôte, hors de la boîte où l’agent tourne. Cela inclut le trafic du modèle, là précisément où des lignes de journal deviennent des instructions.

La sortie d’outil arrive non fiable

Bromure note le contenu que l’agent lit, y compris le contenu des fichiers, les pages web et les blocs tool_result qui reviennent des serveurs MCP et des commandes shell, avec un modèle local d’injection de prompt. Ce détecteur cherche exactement cela : une ligne de journal portant un impératif adressé à qui la lira. Il note le passage lui-même, donc le fait que Cloudflare le livre via une connexion que vous avez configurée n’apporte rien à la charge utile.

Vous choisissez ce que fait une détection

Log and continue enregistre chaque occurrence dans la fenêtre Security Log et laisse la requête passer. Ask me what to do met en pause la requête sortante et vous montre le texte signalé, pour que vous décidiez avec la phrase sous les yeux. Block arrête unilatéralement avant que le modèle ne la lise, et l’agent reçoit un 451 sec qu’il rapporte comme une panne d’API.

Les fichiers d’autorité ont leur propre classifieur

L’empoisonnement de configuration était l’autre moitié de la divulgation DEF CON. Un classifieur ModernBERT affiné note les fichiers qu’un agent traite comme des consignes permanentes, CLAUDE.md et AGENTS.md et GROK.md et leurs variantes imbriquées et globales, aux côtés d’un scanner déterministe pour les charges utiles à largeur nulle, bidirectionnelles et en balises Unicode qu’aucun modèle ne peut lire.

Tout reste sur votre Mac

Les deux détecteurs tournent sur l’appareil, à partir de modèles que vous téléchargez une fois depuis bromure.io. Noter vos journaux WAF de production à la recherche d’instructions injectées n’implique d’envoyer vos journaux WAF de production nulle part.

L’écriture exige une clé qui n’est pas dans la machine

Supposons qu’une charge utile passe malgré tout. Le bout de cette chaîne est un appel d’API qui modifie un enregistrement DNS, et cet appel a besoin d’un identifiant.

Dans un profil Bromure, il n’est pas là à prendre. Un jeton Cloudflare y entre comme une entrée Other API keys, ce qui génère une fausse valeur brm_… et l’exporte dans la VM sous le nom de variable d’environnement de votre choix. Le vrai jeton reste sur l’hôte, et le proxy le substitue sur le fil, sur les requêtes sortantes vers le seul hôte de destination auquel vous l’avez lié. Le processus de l’agent ne le détient jamais. Un dotfile ou un historique de shell non plus.

Activez Require approval to use pour cette entrée et chaque substitution lève une boîte de dialogue sur macOS, hors de la VM, avant que Bromure ne transmette la vraie valeur. Un agent détourné peut composer une mise à jour DNS bien formée, et il ne peut pas répondre à la boîte de dialogue.

Le reste du rayon d’action a une réponse plus stricte. Guardrails est un moteur de politique qui tourne dans le proxy de l’hôte et retire les opérations destructrices des protocoles que parle l’agent : Kubernetes, AWS, DigitalOcean, registres de conteneurs, GitHub, GitLab, Bitbucket et les endpoints HTTPS de bases de données. Choisissez Block destructive ou Read-only par ressource, et un appel bloqué revient en 403 sec. Comme c’est l’hôte qui prend cette décision, un agent qui suit les instructions de quelqu’un d’autre à l’intérieur de la VM n’a rien à désactiver.

Sur le portable du développeurla ligne de journal arriveserveur MCP first-party, donc digne de confiancerien ne lit le texte lui-mêmele jeton est juste làCLOUDFLARE_API_TOKEN, actif, utilisablel’écriture DNS part et réussitet aucune alerte ne partutilisateur autorisé, agent autorisé,jeton autorisé, appel autoriséDans un profil Bromurela ligne est notée à l’arrivéeun modèle local lit le texte, pas l’expéditeurdemander, ou bloquer avec un 451 secle jeton n’est pas dans la VMl’env contient brm_…, la vraie valeur sur l’hôtela substitution ouvre un dialogue sur macOSet la chaîne est une liste de ligneshôte, statut, latence, rapport de substitutionpar requête, dans le Trace Inspector
Le même agent détourné, sur deux machines. Sur le portable d’un développeur, le jeton est dans l’environnement et l’appel part. Dans un profil Bromure, la ligne de journal est notée à l’arrivée, l’environnement ne contient qu’un substitut, le vrai jeton est injecté sur l’hôte derrière une boîte de dialogue de consentement, et tout l’échange est une ligne dans le Security Log.

Un bug de bac à sable ne déplace pas un hyperviseur

La conférence a aussi divulgué une faille zero-day de Claude qui contourne le bac à sable réseau de l’agent pour une exfiltration complète de données, plus des rootkits agentiques assemblés à partir d’injection en mémoire et d’empoisonnement de configuration qu’aucun EDR ne repère. Les deux constats pointent le même point faible : le confinement livré avec un agent est atteignable depuis l’intérieur.

Bromure place la frontière ailleurs. La frontière est une machine virtuelle, tournant sur l’hyperviseur d’Apple avec son propre noyau, en NAT, chaque paquet traversant un proxy qui s’exécute sur macOS. Un défaut dans le bac à sable in-process de l’agent est un défaut à l’intérieur de la VM. Il ne déplace pas la VM, et il ne donne pas au code dans la VM une route vers le réseau qui contourne le proxy de l’hôte.

Et quand quelque chose y atterrit malgré tout, cela atterrit sur une machine construite pour être jetée. Erase home efface /home/ubuntu, c’est-à-dire les dotfiles, .ssh, npm-global, .cargo et l’historique du shell, et le remet dans son état d’après-clonage. Reset to base abandonne tout changement au niveau système et re-clone le disque de travail depuis l’image de base. Le rootkit qu’aucun scanner ne trouve reste dans une couche de disque que vous pouvez supprimer.

La chaîne invisible, écrite noir sur blanc

L’observation la plus forte de Tenet est que la chaîne se cache à la vue de tous parce que chacune de ses étapes est légitime. Il n’y a ni signature ni anomalie à corréler.

Bromure n’essaie pas d’en corréler une. Chaque requête émise par la VM traverse le proxy de l’hôte, et Bromure enregistre l’hôte, le statut, la latence et les identifiants qu’il a substitués. Les détections d’injection atterrissent dans le Security Log avec le texte signalé en pièce jointe. Montez le niveau de trace et Bromure conserve aussi les corps des requêtes IA, chiffrés avec la même clé de trousseau que les secrets de votre profil.

Vous pouvez alors poser une autre question : qu’est-ce que cette session a touché. Un agent qui a passé l’après-midi à lire des journaux Cloudflare puis a fait son tout premier appel à l’API DNS, ce sont deux lignes que vous pouvez lire, sur la machine où la session a tourné, sans agent à déployer ni SIEM vers lequel router.

Cloudflare ajustera sa surface, Sentry la sienne, et les deux chaînes de la conférence de vendredi se refermeront. Associez n’importe quel système qui enregistre des entrées hostiles à n’importe quel agent qui lit des enregistrements pour faire son travail, et vous avez reconstruit cette attaque à partir de deux pièces qui font toutes deux leur travail. Vous gardez des journaux pour que quelqu’un les lise, et ce lecteur est désormais un programme qui agit sur ce qu’il y trouve.

Un réflexe suffit : traitez tout ce que l’agent lit comme quelque chose qu’un inconnu a pu écrire, y compris les parties que vos propres défenses ont consignées.

Installez Bromure Agentic Coding, et mettez entre le journal et l’agent quelque chose qui vérifie le texte.