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

La passerelle acceptait n'importe quel jeton

Le 2 septembre, la CISA a ajouté sept failles exploitées au catalogue KEV. Trois relèvent de l'infrastructure IA, le premier lot où l'IA pèse près de la moitié. Lisez l'entrée LiteLLM : son point d'accès MCP admettait une requête non authentifiée porteuse de n'importe quel jeton Bearer, parce qu'un contrôle de clé en échec retombait sur un objet d'authentification vide, et l'appelant pouvait ensuite lister et invoquer tous les outils câblés à la passerelle. Bromure Agentic Coding place la même autorité derrière un hyperviseur et un vsock, sans port en écoute, sans en-tête à forger et sans branche de repli.

Vous aviez bâti la passerelle pour qu'aucun portable ne détienne à lui seul toutes les clés. Ça a marché, et elle détenait toutes les clés. Puis sa porte d'entrée a accepté un jeton Bearer que quelqu'un venait d'inventer.

Le 2 septembre, la CISA a ajouté sept vulnérabilités au catalogue des Known Exploited Vulnerabilities. Deux bugs SonicWall SMA1000, une injection SQL dans Sangoma Switchvox, un contournement d'authentification dans JFrog Artifactory, une injection de commande OS dans Kestra, une faille de smuggling HTTP dans Starlette, et un défaut d'authentification dans le LiteLLM de BerriAI.

Trois de ces sept relèvent de l'infrastructure IA et ML. Forkast y a vu le premier lot KEV où les composants IA représentent près de la moitié des ajouts, le genre de jalon qui vaut un titre puis part au classement. Regardez de quelle infrastructure IA il s'agit et le lot mérite mieux que le classement. Les trois se tiennent au milieu : ce sont les composants que vous déployez pour que vos agents et les ressources qu'ils touchent cessent de se parler directement. Commencez par l'entrée LiteLLM.

La branche de repli

LiteLLM est une passerelle IA : un proxy unique qui s'intercale entre vos agents et les fournisseurs de modèles, détient les clés fournisseur pour que personne d'autre n'ait à le faire, applique budgets et limites de débit, écrit les journaux, et désormais essaime vers des serveurs Model Context Protocol pour que les agents d'une équipe partagent un seul point d'accès MCP au lieu que chaque développeur câble le sien.

CVE-2026-59822, publiée le 8 juillet et assortie d'un CVSS de 8.8 dans l'avis GitHub, vit sur ce point d'accès MCP. Une phrase de l'avis porte toute l'histoire :

le chemin de repli pouvait remplacer une validation de clé LiteLLM en échec par un objet UserAPIKeyAuth() vide.

Le point d'accès MCP Streamable HTTP prenait en charge le passthrough OAuth2, afin qu'un jeton destiné à un serveur MCP en amont puisse traverser la passerelle plutôt que d'être validé contre le magasin de clés propre à LiteLLM. C'est une fonctionnalité raisonnable, et elle exige une branche : essayer d'abord la clé LiteLLM, et prendre le chemin passthrough quand ce n'est pas une clé qui est arrivée.

On atteint cette branche en échouant. Envoyez un en-tête Authorization contenant n'importe quelle chaîne, la validation de clé la rejette parce que la chaîne n'est pas une clé, et le gestionnaire construit un UserAPIKeyAuth() vide et poursuit avec. Votre requête détient désormais une session MCP authentifiée n'appartenant à personne. À partir de là, vous énumérez tous les outils MCP dont la passerelle a été dotée et vous les appelez : applications internes, bases de données, consoles cloud, systèmes de développement, tout ce que l'équipe avait raccordé. La faille touche toutes les versions antérieures à 1.84.0. L'échéance de remédiation fixée par la CISA aux agences fédérales est le 16 septembre, et le conseil de LiteLLM à qui ne peut pas mettre à jour aujourd'hui est de bloquer /mcp/ au niveau du reverse proxy placé devant.

CVE-2026-59822 — la branche que l'échec atteintrequête non authentifiéePOST /mcp/Authorization: Bearer anything-at-allvalider la clé LiteLLMla chaîne n'est pas une clééchec de la validationrepli passthrough OAuth2substitue un objet d'auth vide et poursuitUserAPIKeyAuth()session MCP authentifiée, n'appartenant à personnelister tous les outils configurés · en appeler n'importe lequel · aucune clé LiteLLM présentéeapplications internesderrière la passerellebases de donnéestout ce qui était câbléservices cloudavec toute sa portéesystèmes de dév.sources, CI, tickets
Le gestionnaire MCP essayait d'abord la clé LiteLLM et, en cas d'échec, prenait le chemin passthrough OAuth2, qui construisait un UserAPIKeyAuth() vide et poursuivait. Une requête porteuse d'un jeton Bearer inventé arrivait là où une clé valide serait arrivée : une session MCP authentifiée, avec derrière elle toute la liste d'outils de la passerelle.

Les trois autres ont cassé dans la même fonction

Lisez le reste du lot et vous obtenez quelque chose de plus utile que le titre IA-contre-pas-IA.

Starlette, CVE-2026-48710, surnommée BadHost. Starlette est la boîte à outils ASGI sous FastAPI, sur laquelle est bâtie une large part des services IA en Python, LiteLLM compris. Un en-tête Host forgé injecte un chemin dans la partie hôte de la requête, ce qui déplace la façon dont l'URL est reconstruite, ce qui signifie qu'un middleware d'authentification par chemin évalue une route pendant que l'application en sert une autre. L'entrée de la CISA énonce le résultat : contournement d'authentification, quand l'authentification dépend du chemin de l'URL reconstruite. Elle porte un CVSS de 6.5, le score le plus bas du lot et celui qui dit le moins sur la conséquence. LiteLLM a livré son propre correctif compagnon pour la même forme en 1.84.0, en la décrivant comme « un en-tête Host forgé pouvait amener la barrière d'authentification du proxy à évaluer une autre route que celle servie », et a dit aux opérateurs dont le proxy avait été exposé de faire tourner leurs clés et d'auditer les journaux d'administration.

JFrog Artifactory, CVE-2026-82329, CVSS 9.8. Défaut d'authentification sous la configuration par défaut : une clé de jonction « fantôme » qui permet à un attaquant non authentifié de forger des jetons d'administrateur. watchTowr a documenté une exploitation dans la nature le 1er septembre, quatre jours après la divulgation, avec des attaquants qui frappaient des identifiants admin et énuméraient les utilisateurs. C'est le dépôt d'artefacts, l'hôte qui répond à npm install et pip install pour toute l'organisation.

Kestra, CVE-2026-49869. Injection de commande OS accessible à un attaquant distant non authentifié, qui peut créer et exécuter des workflows arbitraires sans le moindre identifiant. L'orchestrateur fait ce que fait un orchestrateur, pour le compte de quelqu'un qui ne s'est jamais connecté.

Quatre produits, quatre bases de code différentes, et la même fonction cassée dans chacune : celle qui décide si cette requête a le droit d'être là. Un objet d'authentification vide. Un chemin reconstruit. Une clé de jonction par défaut. Dans le cas de Kestra, aucun contrôle du tout sur la route qui exécute.

Ce que les attaquants ont fait ensuite était ennuyeux, et l'ennui est le signe du travail en volume. The Hacker News a rassemblé les comportements observés : reverse shells, mineurs XMRig, énumération d'identifiants, et vol de clés d'API et d'identifiants de fournisseurs de LLM. Microsoft l'a résumé :

Les objectifs observés étaient constants. Dans tous les cas, la télémétrie a montré de la collecte d'identifiants, des mécanismes d'accès durable et de la monétisation de ressources, même si le chemin d'exécution différait selon le produit.

Un lot, une fonction, quatre façons de se tromperCOMPOSANTLE CONTRÔLE QUI DÉCIDAITCE QU'IL A LAISSÉ PASSERLiteLLM · passerelle IACVE-2026-59822 · 8.8valider la clé API LiteLLMsur le point d'accès MCPn'importe quel jeton Bearerl'échec retombait sur un objet d'auth videStarlette · outils ASGICVE-2026-48710 · 6.5middleware d'auth par cheminsur l'URL reconstruiteune route jamais protégéeun en-tête Host forgé a déplacé la reconstructionJFrog Artifactory · registreCVE-2026-82329 · 9.8validation de la clé de jonctionsous la configuration par défautdes jetons d'administrateur forgésexploité dans la nature quatre jours aprèsKestra · orchestrateurCVE-2026-49869aucun, sur la route qui exécutecréer et exécuter un workflowcommandes arbitraires, sans authaucun identifiant requis
Quatre entrées d'un même lot KEV, quatre bases de code, une seule fonction. Chaque produit a cassé à l'endroit où il décide si une requête a sa place, et trois des quatre sont des composants que vous déployez pour centraliser les accès au lieu de laisser chaque développeur détenir les siens.

La passerelle était la bonne idée, et voici sa facture

La passerelle IA est l'une des meilleures idées de ces deux dernières années, et la plupart des équipes y sont venues pour de bonnes raisons.

Avant la passerelle, l'agent de code de chaque développeur détenait une clé fournisseur dans une variable d'environnement, chaque développeur câblait ses propres serveurs MCP avec ses propres jetons, et personne ne pouvait dire ce que tout cela avait dépensé ou touché. Mettre une passerelle au milieu règle tout ça d'un coup. Un seul endroit détient les clés fournisseur et la configuration MCP, et écrit le journal. Faire tourner une clé devient une opération unique, et couper l'accès à un employé qui part aussi. L'industrie a convergé là-dessus pour de bonnes raisons.

La facture, c'est que vous avez bâti un service réseau dont le but même est de détenir l'autorité pour tout le monde, et qui décide qui vous êtes avec une fonction. Les fonctions ont des branches, et l'une d'elles traite le cas où la première chose que vous avez essayée n'a pas marché.

LiteLLM n'a pas inventé cette forme. Toute passerelle a une porte d'entrée, toute porte d'entrée a une fonction d'authentification, et une fonction d'authentification qui prend en charge deux schémas d'identification a un chemin qu'elle emprunte quand le premier échoue. La portée qui se tient derrière cette porte est délibérée : la concentrer, c'est le produit. Alors quand une passerelle a des ennuis, tout ce qu'elle détient est déjà dans la pièce.

La conclusion qu'on tire d'habitude d'un incident pareil est « revenons aux clés par développeur », ce qui est pire sur toutes les mesures possibles. Continuez à centraliser. La question qui mérite débat est où se trouve la chose centralisée, et si elle doit répondre à des requêtes d'inconnus pour faire son travail.

Où Bromure place le même travail

Bromure Agentic Coding exécute chaque agent de code dans une VM Linux virtualisée matériellement sur votre propre Mac, et chaque contrôle de sécurité se tient du côté hôte de cette frontière. Les contrôles sont la même liste que propose une passerelle : détenir les identifiants, arbitrer les serveurs MCP, classer ce que l'agent fait avec votre infrastructure, tenir le registre. Rien sur aucun réseau ne peut atteindre le composant qui les applique.

Il n'y a pas de porte d'entrée. Le HTTPS de l'invité ne part jamais sur le réseau. Il passe par un socket virtio, le port vsock 8443, jusqu'au proxy hôte, et le manuel est catégorique sur la topologie : la VM n'a aucune autre route vers le réseau. Le proxy ne détient aucun port en écoute que votre LAN, votre réseau d'entreprise ou l'internet puissent adresser. Il ne demande jamais qui appelle, parce qu'une seule chose se tient à l'autre bout de ce socket et que l'hyperviseur décide de ce qu'est cette chose. Pas d'en-tête Authorization, pas de magasin de clés, pas de négociation de schéma, et donc aucune branche à prendre quand le premier schéma échoue.

Le jeton bearer MCP est un leurre avant même d'atteindre l'agent. Pour les serveurs MCP à transport HTTP configurés dans un espace de travail, le vrai jeton bearer reste chiffré sur le Mac. La configuration de l'agent reçoit un substitut brm-mcp_…. Le panneau des réglages étiquette ce champ Jamais envoyé à la VM — remplacé par le proxy, et le proxy hôte substitue la vraie valeur sur le fil, cantonnée en correspondance exacte ou sous-domaine à l'hôte de ce serveur et à aucun autre. Le proxy répond aussi 404 aux chemins de découverte OAuth et OIDC du serveur, si bien que Claude Code traite le serveur comme pré-authentifié au lieu de tenter un flux navigateur que la VM ne pourrait jamais achever. Le repli de LiteLLM se tenait sur cette même surface de passthrough. Ici, l'espace de travail ne détient aucun identifiant à laisser tomber.

Chaque opération obtient sa propre décision. Une passerelle règle la question à la porte : passez-la, et tout ce qui est derrière est à vous. Les Guardrails de Bromure classent les appels de l'agent à l'intérieur du proxy, à travers Kubernetes, AWS, les forges git, les registres de conteneurs et les bases de données, et appliquent une politique d'écriture par service. Les nouveaux espaces de travail sont par défaut sur Demander avant écriture, si bien que les lectures passent et que chaque mutation s'arrête sur une boîte de dialogue côté hôte montrant l'opération littérale : le SQL exact, ou MÉTHODE /chemin. Lecture seule bloque toute mutation. Demander avant usage verrouille l'identifiant lui-même, avec des autorisations qui se comptent en minutes. Une session forgée ne peut toujours pas se frayer un kubectl delete à travers quoi que ce soit, parce que la deuxième décision se prend sur votre Mac et ne doit rien à la façon dont la première s'est passée.

Le refus par défaut répond à la joignabilité, dans les deux sens. Le pare-feu de sortie de l'espace de travail est une table de règles ordonnée avec un défaut pour le trafic non apparié. Mettez-le sur Refuser et la VM atteint les hôtes que vous avez listés et rien d'autre, sur n'importe quel protocole. Deux composants hors de l'invité l'appliquent : le commutateur virtuel apparie chaque flux par IP de destination et par nom d'hôte capté dans le DNS, et le proxy apparie de nouveau par nom de serveur TLS. Les modifications atteignent les sessions en cours sans redémarrage. Dans l'autre sens, le mode NAT garde les VM hors de votre LAN physique, et rien de l'extérieur n'ouvre de connexion vers elles à moins que vous ne publiiez un service exprès. Les scanners qui ont ramassé ces passerelles exposées n'obtiennent aucune réponse d'un Mac.

Tout ce qu'une passerelle compromise renvoie est une entrée non fiable. Cette partie survit à la CVE. Une fois qu'une passerelle appartient à quelqu'un d'autre, sorties de modèle, résultats d'outils et chaînes d'erreur arrivent tous d'un attaquant, sur le fil le plus privilégié de la pile : celui sur lequel l'agent est bâti pour agir. Le détecteur de code source de Bromure note les segments tool_result dans le trafic IA sortant de l'agent avec un modèle PromptGuard local, sur l'appareil, avant que le modèle n'agisse dessus, et peut journaliser, demander ou bloquer ; un blocage renvoie un HTTP 451 et le modèle ne voit jamais le contenu.

La jambe d'exfiltration échoue en position fermée. Chaque identifiant d'un espace de travail est un leurre déterministe avec une seule destination légitime. Le proxy inspecte chaque requête sortante à la recherche d'un leurre parti là où il n'a pas été frappé ; quand il en trouve un, il refuse la requête sans transmettre un octet, met la VM en pause et lève une alerte, journalisée comme une ligne rouge Courtage d'identifiants dans la Security Timeline. Comme seul le leurre a jamais été à portée, le vrai identifiant n'a pas besoin d'être renouvelé.

l'autorité au milieuun service, joignable par tout ce qui sait l'atteindreagent · poste Aagent · poste Bun inconnujeton inventépasserelle IAà l'écoute sur :443la fonction d'auth lit un en-têtedétient toutes les clés APIdétient tout le câblage MCPune branche décide de toutfournisseurs de modèles · bases · cloud · applis internesatteints avec l'autorité de la passerelle, pas celle de l'appelantce qu'il faut à un attaquantune route vers le port, et une mauvaise branche dans le contrôlel'autorité en périphérieun Mac, un hyperviseur, rien à l'écouteVM de l'espace de travail · l'agent tourne icibrm-mcp_… · sk-ant-api03-brm-… · ghp_…des leurres seulement — aucun secret réel dans l'invitévsock 8443 — la seule sortieproxy hôte · sur votre Macaucun port en écoute · aucun en-tête à forger · aucun replisubstitue le vrai identifiant, cantonné à un seul hôtepare-feu de sortie · politique d'écriture · scan d'injectionune ligne de trace par requête, sur votre machinece qu'il faut à un attaquantune route qui n'existe pas, vers un port qui n'est pas ouvert
À gauche : l'autorité au milieu. Un service réseau détient toutes les clés et tout le câblage MCP, et une seule fonction d'authentification se tient entre lui et quiconque sait le router. À droite : l'autorité en périphérie. Les mêmes contrôles tournent sur votre Mac derrière un hyperviseur, joints par un socket virtio sans port en écoute. La VM ne détient que des leurres, et le proxy tranche chaque opération après que la requête a quitté l'invité.

Si vous exploitez une passerelle aujourd'hui

Passez LiteLLM en 1.84.0 ou plus récent ; si vous ne pouvez pas, bloquez /mcp/ au niveau du reverse proxy placé devant. Puis suivez le conseil que LiteLLM donne lui-même pour le correctif d'en-tête Host et traitez un proxy exposé comme un magasin de clés exposé : renouvelez les clés fournisseur qu'il détenait, auditez les journaux d'administration. Les agences fédérales ont jusqu'au 16 septembre sur la CVE-2026-59822, une date raisonnable à emprunter.

La règle qui rétrécit la question

Dans le panneau Guardrails de l'espace de travail, mettez Trafic non apparié sur Refuser et listez ce dont la tâche a besoin : allow web api.github.com, allow web registry.npmjs.org, default deny. Un espace de travail qui n'a pas le droit d'atteindre une passerelle interne ne peut pas servir à en traverser une, et l'enregistrement pousse la politique vers les sessions en cours sans redémarrage.

Détenir le secret, ne pas le vérifier

Une ligne des notes d'architecture de Bromure mérite une relecture après une semaine comme celle-ci :

Contourner la frontière ne rapporte rien à un attaquant, parce que la frontière n'est pas l'endroit où les secrets sont vérifiés — c'est le seul endroit où les secrets existent.

Une passerelle est un endroit où les identifiants sont vérifiés : une requête arrive, une fonction l'inspecte, et le verdict de cette fonction est la seule chose qui se tienne entre l'appelant et les clés. Les vérifications ont des cas limites et des chemins de repli. Les vérifications valent une CVE, une entrée KEV et une échéance fédérale, puis en valent une autre deux mois plus tard sur une autre branche de la même fonction.

Une frontière matérielle est un endroit où les identifiants sont. Rien n'arrive pour être inspecté, donc aucun verdict ne peut se tromper. Le vrai jeton reste chiffré sur un Mac, l'espace de travail détient un substitut brm- qui ne vaut rien nulle part, et la substitution se produit sur un socket où un seul hyperviseur peut écrire.

Nous avons écrit des variations de ceci trois fois en six semaines : un proxy de sortie qui a fait confiance à un nom d'hôte que l'agent pouvait écrire, un garde-fou de commandes qui lisait bash autrement que bash, et trois agents de code dont les contournements finissaient tous sur un vrai identifiant dans un processus. Chaque fois, le composant défaillant faisait honnêtement son travail d'évaluer quelque chose, et c'est ça la constante. L'évaluation est une primitive plus faible que l'absence, et nous continuons à confier à l'évaluation le travail que l'absence fait gratuitement.

Centraliser l'autorité de vos agents était le bon choix. Placez la chose centralisée là où personne ne peut lui envoyer de requête. Installez Bromure Agentic Coding et donnez à chaque agent une frontière sans porte d'entrée.