
Blog über CVE-2026-59827, unsichere Deserialisierung der H2-Abfrageausgabe
GHSA-w95f-x9v9-wv36 | CVSS 9.9 Kritisch | CWE-502: Deserialisierung nicht vertrauenswürdiger Daten
CVE-2026-59827 ist eine kritische Sicherheitslücke zur Remote-Code-Ausführung in Metabase, der beliebten Open-Source-Plattform für Business Intelligence und Datenanalyse. Der Fehler liegt in der Art und Weise, wie Metabase Abfrageergebnisse verarbeitet, die von einer H2-Datenbankverbindung zurückgegeben werden. Wenn eine native SQL-Abfrage gegen eine H2-Quelle eine Spalte vom Typ OTHER zurückgibt, deserialisiert Metabase die Rohbytes dieser Spalte in ein Java-Objekt, ohne eine Validierung durchzuführen. Ein authentifizierter Benutzer, der native Abfragen ausführen kann, kann daher eine bösartige serialisierte Nutzlast in die Ergebnismenge einschleusen und eine beliebige Code-Ausführung auf dem Server auslösen, der Metabase hostet.
Der Sicherheitslücke wurde ein CVSS-Score von 9,9 zugewiesen, was die minimalen Voraussetzungen und die vollständige serverseitige Code-Ausführung widerspiegelt, die aus einer erfolgreichen Ausnutzung resultiert.
Metabase bietet zwei parallele Editionen aus demselben Release-Zyklus an. Die Open-Source-Edition verwendet Versionsnummern mit dem Präfix 0 – zum Beispiel v0.61.1. Die Enterprise-(kommerzielle) Edition verwendet Versionsnummern mit dem Präfix 1 – zum Beispiel v1.61.1. Beide Editionen teilen sich die gleiche Codebasis und werden zusammen veröffentlicht, sodass eine Schwachstelle, die v1.61.0 betrifft, gleichermaßen v0.61.0 betrifft. In diesem Dokument werden Versionsnummern mit dem Enterprise-Präfix 1.xx geschrieben, aber jede betroffene Version bildet direkt auf ihr 0.xx-Open-Source-Pendant ab, indem die führende 1 durch 0 ersetzt wird.
Sowohl CVE-2026-59826 als auch CVE-2026-59827 wurden gemeinsam im Juli 2026 offengelegt. Sie teilen sich überlappende Versionsbereiche, haben jedoch unterschiedliche Patch-Punkte.
Die verwundbaren Enterprise-Versionen sind 1.58.0 bis 1.58.14, 1.59.0 bis 1.59.11, 1.60.0 bis 1.60.6.2 und 1.61.0 bis 1.61.1.3. Die entsprechenden Open-Source-Versionen sind 0.58.0 bis 0.58.14, 0.59.0 bis 0.59.11, 0.60.0 bis 0.60.6.2 und 0.61.0 bis 0.61.1.3.
Ein interner Patch wurde zuerst als 1.61.1.4 (Enterprise) und 0.61.1.4 (Open-Source) veröffentlicht. Die erste öffentlich verfügbare behobene Version in der 1.61-Linie ist 1.61.2 (v1.61.2.x / v0.61.2.x). Metabase Cloud-Instanzen wurden automatisch vom Anbieter gepatcht.
Die verwundbaren Enterprise-Versionen sind 1.55.0 bis 1.58.15.0, 1.59.0 bis 1.59.11, 1.60.0 bis 1.60.6.2 und 1.61.0 bis zur gesamten 1.61.1.x-Linie. Die erste vollständig gepatchte öffentliche Version ist 1.61.2 (v1.61.2.x / v0.61.2.x). Der Umfang von CVE-2026-59826 ist breiter und reicht bis zur 1.55-Release-Linie zurück, was die länger bestehende Präsenz des unzureichend validierten Datenbankerstellungs-Codepfads widerspiegelt, den es ausnutzt.
Der Serialisierungsmechanismus von Java ermöglicht es, ein Objekt im Speicher in einen flachen Bytestrom zu konvertieren, zu speichern oder zu übertragen und später durch Aufruf von ObjectInputStream.readObject() wiederherzustellen. Die kritische Eigenschaft dieses Mechanismus ist, dass die Wiederherstellung Code ausführt. Klassenkonstruktoren, readObject-Überschreibungen und Finalizer werden alle während der Deserialisierung ausgeführt. Wenn die gelesenen Bytes aus einer nicht vertrauenswürdigen Quelle stammen, kann ein Angreifer sie so gestalten, dass sie über eine Sequenz vorhandener, legitimer Klassen, die bereits in der JVM geladen sind, beliebige Methodenaufrufe auslösen. Diese Sequenzen werden als Gadget Chains bezeichnet.
Gadget Chains erfordern nicht, dass neuer Code in die Anwendung eingeführt wird. Sie nutzen die Verdrahtung vorhandener Bibliotheksklassen aus, deren normale Methoden, wenn sie während der Deserialisierung in der richtigen Reihenfolge aufgerufen werden, schließlich zu einer Senke wie Runtime.exec() gelangen. Tools wie ysoserial existieren speziell zur Generierung dieser Payloads für weit verbreitete Bibliotheken wie Apache Commons Collections, Spring Framework und andere.
H2 ist eine reine Java-eingebettete relationale Datenbank. Es definiert einen speziellen SQL-Spaltentyp namens OTHER, der als Durchgang für beliebige Java-Objekte dient. Wenn H2 einen Wert in einer OTHER-Spalte speichert, schreibt es die Bytes, die von Java's ObjectOutputStream erzeugt werden. Wenn es den Wert zurückliest, ruft es ObjectInputStream.readObject() auf, um das Objekt zu rekonstruieren. Die rohen serialisierten Bytes können auch direkt in einer Abfrage unter Verwendung der hexadezimalen Literalsyntax von H2 bereitgestellt werden:
SELECT CAST(X'ACED0005...' AS OTHER);
-- or
SELECT X'ACED0005...'::OTHER;
Das Präfix ACED gefolgt von 0005 ist die magische Nummer des Java-Serialisierungsstroms und die Protokollversion. Jeder Hex-String, der mit ACED0005 beginnt, ist ein Java-serialisierter Objektstrom.
Wenn H2 diese Abfrage verarbeitet, deserialisiert es die Hex-Bytes auf der Datenbankseite. Das resultierende Objekt wird dann über die JDBC-ResultSet an die aufrufende Anwendung zurückgegeben. Wenn die Anwendung den Spaltenwert inspiziert – zum Beispiel, um ihn für die Anzeige zu formatieren – kann dies eine zusätzliche Verarbeitung auslösen. Genau das tut Metabase im verwundbaren Codepfad.
Metabase erhält die JDBC-ResultSet vom H2-Treiber und überprüft die Spaltenmetadaten, um zu entscheiden, wie jeder Wert für den Benutzer dargestellt werden soll. Wenn es auf eine Spalte mit dem JDBC-Typ Types.OTHER (auch als JAVA_OBJECT gemeldet) stößt, versuchen die verwundbaren Versionen von Metabase, die Rohbytes zu deserialisieren, um eine anzeigbare Darstellung zu erzeugen. Dieser Deserialisierungsaufruf, ObjectInputStream.readObject(), wird ohne jegliche Whitelist-Filterung oder Klassenvalidierung ausgeführt.
Die Ablaufreihenfolge ist:
OTHER mit einer manipulierten serialisierten Nutzlast zurückgibt.JAVA_OBJECT-Spalte in der ResultSet zurück.OTHER-Spaltentyp und ruft readObject() für die Bytes auf.Runtime.exec() und führt den Befehl des Angreifers als Betriebssystembenutzer aus, der den Metabase-Prozess ausführt.Die gepatchten Versionen beheben das Problem, indem sie die JDBC-Ergebnis-Metadaten vor jedem Deserialisierungsversuch überprüfen. Wenn eine Spalte als JAVA_OBJECT typisiert ist, lehnt Metabase diese nun direkt ab, anstatt sie zu parsen.