
Blog sur CVE-2026-59827, désérialisation dangereuse de sortie de requête H2
GHSA-w95f-x9v9-wv36 | CVSS 9.9 Critique | CWE-502 : Désérialisation de données non fiables
CVE-2026-59827 est une vulnérabilité critique d'exécution de code à distance dans Metabase, la plateforme open-source populaire de business intelligence et d'analyse de données. Le défaut provient de la manière dont Metabase traite les résultats de requêtes renvoyés par une connexion de base de données H2. Lorsqu'une requête SQL native sur une source H2 renvoie une colonne typée comme OTHER, Metabase désérialise les octets bruts de cette colonne en un objet Java sans effectuer aucune validation. Un utilisateur authentifié pouvant exécuter des requêtes natives peut donc introduire clandestinement une charge utile sérialisée malveillante dans l'ensemble de résultats et déclencher l'exécution de code arbitraire sur le serveur hébergeant Metabase.
La vulnérabilité a reçu un score CVSS de 9,9, reflétant les conditions préalables minimales requises et l'exécution complète de code côté serveur qui résulte d'une exploitation réussie.
Metabase propose deux éditions parallèles issues du même cycle de publication. L'édition open-source utilise des numéros de version préfixés par 0 — par exemple, v0.61.1. L'édition entreprise (commerciale) utilise des numéros de version préfixés par 1 — par exemple, v1.61.1. Les deux éditions partagent la même base de code sous-jacente et sont publiées ensemble, donc une vulnérabilité qui affecte v1.61.0 affecte également v0.61.0. Tout au long de cet article, les numéros de version sont écrits avec le préfixe entreprise 1.xx, mais chaque version affectée correspond directement à son homologue open-source 0.xx en remplaçant le 1 initial par 0.
Les CVE-2026-59826 et CVE-2026-59827 ont été divulguées ensemble en juillet 2026. Elles partagent des plages de versions qui se chevauchent mais ont des points de correctif différents.
Les versions entreprise vulnérables sont 1.58.0 à 1.58.14, 1.59.0 à 1.59.11, 1.60.0 à 1.60.6.2, et 1.61.0 à 1.61.1.3. Les versions open-source correspondantes sont 0.58.0 à 0.58.14, 0.59.0 à 0.59.11, 0.60.0 à 0.60.6.2, et 0.61.0 à 0.61.1.3.
Un correctif interne a d'abord été publié sous les versions 1.61.1.4 (entreprise) et 0.61.1.4 (open-source). La première version corrigée publiquement disponible dans la ligne 1.61 est 1.61.2 (v1.61.2.x / v0.61.2.x). Les instances Metabase Cloud ont été corrigées automatiquement par le fournisseur.
Les versions entreprise vulnérables sont 1.55.0 à 1.58.15.0, 1.59.0 à 1.59.11, 1.60.0 à 1.60.6.2, et 1.61.0 à l'ensemble de la ligne 1.61.1.x. La première version publique entièrement corrigée est 1.61.2 (v1.61.2.x / v0.61.2.x). Le périmètre de CVE-2026-59826 est plus large, remontant jusqu'à la ligne de version 1.55, reflétant la présence plus ancienne du chemin de code de création de base de données insuffisamment validé qu'elle exploite.
Le mécanisme de sérialisation Java permet de convertir un objet en mémoire en un flux d'octets plat, de le stocker ou de le transmettre, puis de le reconstruire ultérieurement en appelant ObjectInputStream.readObject(). La propriété critique de ce mécanisme est que la reconstruction exécute du code. Les constructeurs de classe, les remplacements de readObject et les finalisateurs s'exécutent tous pendant la désérialisation. Si les octets lus proviennent d'une source non fiable, un attaquant peut les façonner pour déclencher des appels de méthode arbitraires via une séquence de classes existantes et légitimes déjà chargées dans la JVM. Ces séquences sont appelées chaînes de gadgets.
Les chaînes de gadgets ne nécessitent pas d'introduire de nouveau code dans l'application. Elles exploitent le câblage des classes de bibliothèques existantes dont les méthodes normales, lorsqu'elles sont appelées dans le bon ordre pendant la désérialisation, atteignent finalement un puits tel que Runtime.exec(). Des outils comme ysoserial existent spécifiquement pour générer ces charges utiles pour des bibliothèques largement déployées telles que Apache Commons Collections, Spring Framework, et d'autres.
H2 est une base de données relationnelle embarquée pure Java. Elle définit un type de colonne SQL spécial appelé OTHER qui agit comme un passe-plat pour des objets Java arbitraires. Lorsque H2 stocke une valeur dans une colonne OTHER, il écrit les octets produits par ObjectOutputStream de Java. Lorsqu'il relit la valeur, il appelle ObjectInputStream.readObject() pour reconstruire l'objet. Les octets sérialisés bruts peuvent également être fournis directement dans une requête en utilisant la syntaxe littérale hexadécimale de H2 :
SELECT CAST(X'ACED0005...' AS OTHER);
-- or
SELECT X'ACED0005...'::OTHER;
Le préfixe ACED suivi de 0005 est le nombre magique du flux de sérialisation Java et la version du protocole. Toute chaîne hexadécimale commençant par ACED0005 est un flux d'objets sérialisés Java.
Lorsque H2 traite cette requête, il désérialise les octets hexadécimaux côté base de données. L'objet résultant est ensuite renvoyé à l'application appelante via le ResultSet JDBC. Si l'application inspecte la valeur de la colonne — par exemple, pour la formater en vue d'un affichage — elle peut déclencher un traitement supplémentaire. C'est exactement ce que fait Metabase dans le chemin de code vulnérable.
Metabase reçoit le ResultSet JDBC du pilote H2 et inspecte les métadonnées des colonnes pour décider comment restituer chaque valeur à l'utilisateur. Lorsqu'il rencontre une colonne avec le type JDBC Types.OTHER (également signalé comme JAVA_OBJECT), les versions vulnérables de Metabase tentent de désérialiser les octets bruts afin de produire une représentation affichable. Cet appel de désérialisation, ObjectInputStream.readObject(), s'exécute sans aucun filtrage de liste blanche ni validation de classe.
La séquence des événements est la suivante :
OTHER contenant une charge utile sérialisée conçue.JAVA_OBJECT dans le ResultSet.OTHER et appelle readObject() sur les octets.Runtime.exec() et exécutant la commande de l'attaquant en tant qu'utilisateur du système d'exploitation exécutant le processus Metabase.Les versions corrigées résolvent le problème en inspectant les métadonnées des résultats JDBC avant toute tentative de désérialisation. Si une colonne est typée comme JAVA_OBJECT, Metabase la rejette maintenant carrément plutôt que d'essayer de l'analyser.