système : OPÉRATIONNEL
← retour à tous les hacks
INFRASTRUCTURE MEDIUM NEW

Un correctif incomplet : les fuites d'adresses mémoire reviennent dans les routes récentes de vLLM

Le correctif de la faille critique de parsing d'images dans vLLM a assaini le routeur OpenAI — mais des routes ajoutées quelques semaines plus tard renvoient encore le texte brut des exceptions, fuitant des adresses de tas et rouvrant une primitive de contournement d'ASLR.

2026-07-17 // 7 min affects: vllm, vllm-<=0.22.0, anthropic-api-router, speech-to-text-realtime, multimodal-endpoints

De quoi s’agit-il ?

Le 11 juin 2026, le projet vLLM a publié un avis de sécurité (GHSA-hgg8-fqqc-vfmw) signalé par le chercheur Kai Aizen (SnailSploit). Il documente un correctif incomplet : le patch qui avait refermé une précédente faille critique de parsing d’images dans le routeur compatible OpenAI de vLLM n’a pas été étendu aux routes ajoutées peu après, si bien que ces nouveaux points d’entrée fuitent toujours des adresses mémoire internes vers des appelants distants.

La faille d’origine était grave — une vulnérabilité critique (CVSS 9.8) qui chaînait une fuite d’adresse mémoire avec un débordement de tas d’une bibliothèque d’images pour atteindre l’exécution de code à distance. Son correctif a introduit un assainisseur qui retire les adresses des représentations d’objets dans les messages d’erreur avant qu’ils n’atteignent le client. Ce nouveau constat est classé moyen (CVSS 3.1 base 5.3), avec un impact faible sur la confidentialité et aucun sur l’intégrité ou la disponibilité. La classe de faiblesse est CWE-532, insertion d’information sensible dans un message d’erreur — la même classe que la faille parente. Le code concerné est présent dans les versions de vLLM jusqu’à 0.22.0 incluse.

Comment ça marche

Lorsque vLLM analyse une image malformée, la bibliothèque d’imagerie lève une erreur dont le texte contient la représentation en mémoire de l’objet tampon — quelque chose comme cannot identify image file <_io.BytesIO object at 0x7a95e299e750>. Cette valeur hexadécimale finale est une adresse de tas vivante. Si elle atteint le client telle quelle, un attaquant apprend où se situent les objets dans l’espace d’adressage du processus, réduisant l’entropie de l’ASLR de quelque quatre milliards de possibilités à une poignée — exactement l’étape de reconnaissance sur laquelle reposait le chaînage critique d’origine.

Le correctif parent a ajouté une fonction utilitaire sanitize_message et l’a câblée dans les gestionnaires d’exception du routeur OpenAI, réécrivant <_io.BytesIO object at 0x...> en <_io.BytesIO object>. Le problème est que plusieurs chemins de réponse ajoutés au même moment ou après ne l’appellent jamais. L’avis liste cinq de ces emplacements : le point d’entrée « messages » compatible Anthropic, son point d’entrée de comptage de jetons, le convertisseur de flux server-sent-events, et deux chemins d’erreur du WebSocket de reconnaissance vocale en temps réel. Chacun renvoie str(exception) directement à l’appelant.

Une question naturelle : pourquoi le gestionnaire d’exception global et assainissant de vLLM n’intercepte-t-il pas ces cas ? La réponse tient à un détail subtil du framework, qu’il vaut la peine d’intégrer : un gestionnaire d’exception global ne se déclenche que pour les exceptions non gérées qui remontent hors d’une route. Chaque route HTTP concernée attrape au contraire l’exception à l’intérieur de la fonction de route et construit sa propre réponse ; le gestionnaire assainissant n’est donc jamais invoqué. Les chemins WebSocket le contournent pour une autre raison — les trames WebSocket ne traversent pas du tout la chaîne de gestion d’exceptions HTTP. Le même déclencheur d’image malformée qui alimentait la faille parente atteint toutes ces routes récentes sans modification.

L’avis est explicite : il ne s’agit pas de code hérité obsolète, mais d’une série d’oublis de périmètre. L’assainisseur est arrivé le 9 janvier 2026 ; le routeur Anthropic a été ajouté six jours plus tard sans lui, le point d’entrée de comptage de jetons environ deux mois après, et les chemins de reconnaissance vocale en mai — chacun reproduisant le motif non assaini.

Pourquoi c’est important

À elle seule, une fuite d’adresse ne change rien de visible pour l’utilisateur. Sa valeur réside dans son rôle de brique élémentaire. Le chaînage parent avait précisément besoin de cette primitive pour vaincre l’ASLR avant de déclencher une corruption mémoire. Cette seconde étape — un débordement de tas dans un ancien codec d’images — est corrigée dans les versions récentes des bibliothèques ; sur une pile entièrement à jour, ce constat est donc une primitive de divulgation d’information plutôt qu’une voie vers l’exécution de code. Mais vLLM est fréquemment livré dans des images Docker personnalisées, des reconstructions dérivées et des distributions LTS à longue durée de vie qui figent d’anciennes bibliothèques système. Sur tout déploiement embarquant encore un codec d’images vulnérable, ces nouveaux points d’entrée réactivent discrètement la chaîne complète « fuite puis corruption » que le correctif initial devait refermer.

La leçon plus large porte sur la manière dont les correctifs se dégradent. Un patch appliqué à des points d’appel précis ne protège que ces points d’appel. À mesure que de nouvelles routes, de nouveaux transports et de nouveaux points d’entrée sont ajoutés, ils réintroduisent le motif même que le correctif devait éliminer — à moins que la mitigation ne vive à un point de passage obligé par lequel transite toute réponse.

Défenses

Le correctif définitif consiste à mettre à jour vers une version de vLLM incluant la remédiation fusionnée dans la pull request de correction du projet. Au-delà de la mise à jour, les recommandations de l’avis se généralisent bien et rejoignent les conseils d’OWASP sur la divulgation d’informations sensibles :

  1. Assainissez la sortie d’erreur de façon symétrique. Tout chemin qui renvoie du texte d’exception à un client — routes HTTP, convertisseurs de flux et gestionnaires WebSocket — doit nettoyer les représentations d’objets et les adresses brutes. Un correctif sur un seul routeur n’est pas un correctif partout.
  2. Déplacez la mitigation vers un point de passage obligé. Les blocs try/except locaux à une route et les gestionnaires WebSocket contournent les gestionnaires d’exception du framework. Un middleware de réponse qui nettoie tout corps d’erreur sortant prévient toute cette classe de régression, de sorte qu’une route nouvellement ajoutée ne puisse pas rouvrir la fuite en silence.
  3. Élargissez le motif de nettoyage. Une expression régulière qui ne matche que le suffixe d’adresse CPython exact en minuscules est fragile ; des exécutions futures, des extensions C ou des méthodes __repr__ personnalisées peuvent produire des formats non correspondants. Retirez toute adresse hexadécimale isolée plutôt qu’une forme précise.
  4. Ne renvoyez jamais d’erreurs internes brutes à des appelants non fiables. Journalisez l’exception détaillée côté serveur ; renvoyez une erreur générique et opaque au client. Fuites d’adresses, traces de pile et chemins de fichiers sont autant de renseignements pour l’attaquant.
  5. Traitez les suivis de correctifs incomplets comme prioritaires. Quand un bug critique est corrigé, auditez chaque chemin frère et chaque route nouvellement ajoutée à la recherche du même point de sortie avant de refermer le dossier.

Statut

ÉlémentRéférenceDateNotes
Avis de suivi publiéGHSA-hgg8-fqqc-vfmw2026-06-11Divulgation d’information (CWE-532) ; CVSS 5.3 moyen ; aucun CVE attribué
Vulnérabilité parenteCVE-2026-22778 / GHSA-4r2x-xpjr-7cvv2026Critique (CVSS 9.8) ; fuite chaînée à un débordement de tas pour RCE
Assainisseur introduitvLLM PR #319872026-01-09Appliqué au seul routeur OpenAI
Versions affectéesvLLM ≤ 0.22.0Routeur Anthropic, comptage de jetons, convertisseur SSE, WebSocket vocal
CorrectifvLLM PR #451192026Applique l’assainissement aux emplacements oubliés

La morale est une vieille maxime dans un cadre nouveau : un correctif ne vaut que par la surface qu’il couvre. Assainissez la sortie d’erreur en un point unique par lequel passe toute réponse, gardez l’état interne brut hors des messages destinés au client, et lorsque vous corrigez un bug critique, traquez chaque route qui partage son point de sortie avant de le déclarer refermé.

Les détails proviennent de l’avis de sécurité vLLM et des pull requests référencées. Aucun payload de démonstration n’est reproduit ; les défenseurs doivent consulter l’avis lié pour évaluer leur exposition.

Sources