Vier CVEs in pgAdmin lassen eine Anfrage bestimmen, an welchen Server das Passwort geht
Version 9.18 von pgAdmin 4, veröffentlicht am 17. September, bringt 29 Korrekturen, vier davon sicherheitsrelevant und nummeriert von CVE-2026-86861 bis CVE-2026-86864. Zusammen gelesen beschreiben sie ein Thema und nicht vier unabhängige Fehler: Ein vom Aufrufer gelieferter Wert wurde von Code vertraut, der anschließend in fremdem Auftrag mit etwas anderem sprach.
Die Ankündigung beschreibt eine per HTTP-Header behauptete Identität, die für jedes Konto akzeptiert wurde — auch für ein administratives, ganz ohne Anmeldedaten; jetzt ist das opt-in und auf konfigurierte, vertrauenswürdige Proxys beschränkt (CVE-2026-86863). Zwei weitere sind dieselbe Injection in zwei Werkzeugen: ein Datenbankname, der pg_dump als bloßes Positionsargument übergeben wird, wo ein führender Bindestrich ihn in weitere Optionen wie --file verwandelt, und dasselbe Feld an --dbname in Restore und Wartung, wo es die Verbindung — und das exportierte PGPASSWORD — auf einen Server der Wahl des Aufrufers umlenken kann (CVE-2026-86864, CVE-2026-86862). Der vierte ist eine Time-of-Check-to-Time-of-Use-Lücke im Speichern-Endpunkt des File Managers: Ein zwischen Prüfung und open() gesetzter Symlink schrieb außerhalb des Benutzerverzeichnisses (CVE-2026-86861).
Was das bedeutet
Aktualisieren — aber der nützlichere Teil ist, wo diese Fehler sitzen. Keiner davon ist in PostgreSQL. Sie sind im Administrationswerkzeug davor: dem Stück, das mit den Rechten eines Datenbankadministrators läuft, auf einem internen Port erreichbar ist, „weil es ja intern ist", und nach einem anderen Zeitplan gepatcht wird als der Server.
Drei Dinge, die diese Woche etwas bringen:
- Die pgAdmin-Instanzen finden, die niemandem gehören. In jeder Organisation steht eine auf einer Jump-Box, aufgesetzt für eine Migration vor ein paar Jahren. Ein Authentifizierungs-Bypass per Header ist genau der Fehler, der so eine Box in eine Datenbankkonsole verwandelt.
- Prüfen, ob etwas davor Identitäts-Header setzt. Ein Proxy, der einen Header hinzufügt, und ein Werkzeug, das ihn bedingungslos akzeptiert, sind das Paar, das den ersten CVE ausnutzbar macht; jede Hälfte für sich ist vertretbar.
- Davon ausgehen, dass das Passwort unterwegs war. Die beiden Injections lesen keine Daten, sie schicken die Zugangsdaten woandershin. Also die Konten rotieren, die pgAdmin benutzt, und nicht nur patchen: Der Patch schließt den Weg und sagt nichts darüber, was ihn schon gegangen ist.
Und die Designlehre, die diesen Release überdauert: Möglich waren die Injections, weil eine Zeichenkette in einen Argumentvektor und in einen Connection String geriet. Die Korrektur war kein besseres Escaping, sondern der Umzug des Wertes nach PGDATABASE — eine Umgebungsvariable, die libpq nie expandiert. Wenn Benutzereingaben einen Unterprozess erreichen müssen, gewinnt man, indem man einen Kanal findet, der nicht interpretiert wird — nicht indem man einen bereinigt, der es tut.

Das Muster hinter allen vieren
Drei der vier sind ein Fehler in verschiedenen Kleidern: Ein Wert aus der Anfrage landet an einer Stelle, an der Syntax Bedeutung hat. Im Argumentvektor eines Unterprozesses ist ein führender Bindestrich Syntax. In einem Connection String ist ein Semikolon Syntax. In einem Pfad ist ein Symlink Syntax, die das Dateisystem für einen auflöst.
Der vierte — die Time-of-Check-to-Time-of-Use-Lücke — ist der andere Klassiker: Der geprüfte Zustand und der Zustand, auf dem gehandelt wurde, sind nicht derselbe, weil sich dazwischen etwas geändert hat. Einen Pfad prüfen und ihn dann über den Namen öffnen ist das Musterbeispiel; die Korrektur heißt, ein Handle zu halten statt eines Namens.
Was das für selbst gebaute Werkzeuge bedeutet
Administrationswerkzeuge „nur für uns" bündeln Rechte schon dem Entwurf nach, und genau dort überleben solche Fehler am längsten, weil für eine interne Seite niemand ein Bedrohungsmodell schreibt. Zwei Gewohnheiten zahlen sich aus: Benutzereingaben über Umgebung oder Datei an Unterprozesse geben statt über die Kommandozeile — und das Werkzeug Nutzer selbst authentifizieren lassen, statt einem Header zu glauben, den irgendetwas davor gesetzt hat.