Hinter kritischen GitLab-Lücken stecken Fehler in der Regex-Engine von Ruby
Das Ruby-Team hat die Versionen 4.0.9, 3.4.12 und 3.3.13 veröffentlicht. Diese beheben drei Fehler in der Regex-Engine Onigmo, die zur Ausführung von Schadcode auf den betroffenen Servern führen können.
Der prominenteste Fall dafür sind die in den letzten Wochen bekannt gewordenen Lücken bei dem auf Ruby basierenden GitLab. Betroffen ist aber jede Ruby-Anwendung, die reguläre Ausdrücke aus fremden Eingaben erzeugt. Nur wer selbst geschriebene Muster verwendet, muss sich laut Ruby-Team keine Sorgen machen. Bevor Ruby ein Muster auf einen Text anwendet, übersetzt es das Muster in ein internes Programm. In diesem Schritt, dem Kompilieren, liegen die Fehler, nicht erst im Abgleich.
Vier GitLab-CVEs, drei Ruby-Fehler
Das ist bei GitLab der Fall, denn der Dienst kompiliert reguläre Ausdrücke aus Nutzereingaben, etwa aus CI/CD-Konfigurationen. Der Sicherheitsforscher Johan Carlsson meldete über das Bug-Bounty-Programm vier Lücken: CVE-2026-89078 und CVE-2026-93577 mit einem CVSS-Wert von 9,9 sowie CVE-2026-97229 und CVE-2026-110264 mit dem Höchstwert 10,0, beide ohne Anmeldung ausnutzbar. GitLab schloss sie zwischen dem 23. September und dem 21. Oktober, indem es das mitgelieferte Ruby selbst patchte. Das jüngste Update betrifft alle GitLab-Versionen seit 7.0 aus dem Jahr 2014.
Das Ruby-Team ordnet die vier CVEs drei Fehlern zu: Hinter CVE-2026-89078 steckt eine doppelte Speicherfreigabe beim Einlesen eines Musters. Hinter CVE-2026-93577 und CVE-2026-97229 steckt ein Ganzzahlüberlauf bei der Berechnung der Größe des kompilierten Programms und hinter CVE-2026-110264 ein Überlauf interner Zähler bei Mustern mit sehr vielen Wiederholungen.
Keiner der drei Fixes ist neu. Die doppelte Speicherfreigabe ist seit Mai 2025 im Entwicklungszweig korrigiert und steckt seit Ruby 4.0.0 in einer Release-Version. Der Fix für die Zähler hinter CVE-2026-110264 folgte im April 2026, der für die Programmgröße im September 2026. In eine Release-Version schafften es letztere erst jetzt: Ruby 4.0.8 vom 22. Oktober brachte den Fix für die Programmgröße als Teil eines Routine-Updates, ohne ein Wort zur Sicherheit. Einen Tag später erschien 4.0.9 mit dem letzten fehlenden Fix, und die stabilen Zweige 3.4 und 3.3 bekamen alle drei auf einmal. Ruby 3.3 erhält eigentlich nur noch Sicherheitskorrekturen; 3.3.13 erscheint ausdrücklich als Ausnahme, weil GitLab CVEs vergeben hat. Für Ruby 3.2 und älter gibt es keine Updates mehr.
Eine Suchfunktion als Einfallstor
Wie eine Anwendung die gefährdete Stelle erreicht, zeigt eine Suchfunktion in einem Rails-Controller, die eine Liste von Titeln im Speicher filtert:
pattern = Regexp.new(params[:q].to_s)
matches = titles.select { |title| pattern.match?(title) }
Der Parameter q stammt aus der Webanfrage. Mit der Eingabe Rechnung sucht die Anwendung beispielsweise nach diesem Wort, mit ^Rechnung.*2026$ nach Titeln mit passendem Anfang und Ende. Damit kontrollieren Nutzer aber auch das Muster, das Ruby kompiliert, und ein Angreifer kann hier ein präpariertes übergeben. Auf einen Titel angewendet werden muss es dafür nicht: Der Speicherfehler passiert in der ersten Zeile, in Regexp.new. Dasselbe gilt für Regexp.union und für ein interpoliertes Literal wie /#{params[:q]}/.
Im schlimmsten Fall läuft dann Code des Angreifers mit den Rechten des Ruby-Prozesses, also mit allem, auf das die Anwendung selbst Zugriff hat: Datenbank, Secrets aus der Umgebung, Dateisystem. Wahrscheinlicher ist bei einem einzelnen Versuch ein Absturz des Prozesses, der die Anfrage bearbeitet. Wiederholt wird daraus ein Denial of Service ohne Anmeldung. Aktive Angriffe meldet bislang weder GitLab noch Ruby.
Oft braucht so eine Suche die Regex-Engine gar nicht. Wer nur den eingegebenen Text finden will, vergleicht Zeichenketten, und die Eingabe kommt bei Regexp.new nie an:
query = params[:q].to_s
matches = titles.select { |title| title.include?(query) }
Regex-Sonderzeichen gelten dann als gewöhnliche Zeichen, die Suche mit eigenen Mustern entfällt bewusst. Wer eine Eingabe in ein festes Muster einbetten muss, maskiert sie mit Regexp.escape. Sie zählt dann als Folge gewöhnlicher Zeichen, den Aufbau des Musters bestimmt weiter der Entwickler:
pattern = /\A#{Regexp.escape(params[:q].to_s)}/
Timeout hilft nicht, nur das Update
Für fremde Muster empfiehlt die Ruby-Dokumentation bisher ein Timeout, weil sie nur vor Denial of Service warnt. Regexp.timeout bricht aber nur einen Abgleich ab, der zu lange dauert. Die Fehler passieren davor, beim Kompilieren, und das Timeout greift nicht. Eine Begrenzung der Musterlänge hilft laut Ruby-Team ebenfalls nicht zuverlässig, weil einige der Fehler auch kurze Muster auslösen. Wer nicht sofort aktualisieren kann, sollte keine Muster aus fremden Eingaben kompilieren.
Mit einem Versionsmanager ist das Update ein Dreischritt: neue Version installieren, im Projekt eintragen, Gems neu bauen. Mit mise erledigt ein Befehl die ersten beiden Schritte, hier für die Reihe 3.4: Er installiert die Version und trägt sie in mise.toml ein.
mise use ruby@3.4.12
bundle install
Mit rbenv sind es drei Befehle: rbenv install 3.4.12, dann rbenv local 3.4.12 für die Datei .ruby-version, dann bundle install. Wer die Version im Gemfile festnagelt, passt dort die ruby-Zeile an. Docker-Images bekommen einen neuen Tag, Distributionspakete kommen mit eigener Verzögerung, und Bundles wie GitLab Omnibus bringen ihr Ruby mit dem Produkt-Update mit. Ob der Server die neue Version ausführt, zeigt ruby -v.
Keine Ruby-CVEs, keine Scanner-Warnung
Eigene CVE-Kennungen hat das Ruby-Projekt bislang nicht beantragt. Dahinter steht eine Grundsatzfrage: Ruby hat das Kompilieren fremder Muster schon immer als unsicher betrachtet, also als etwas, das eine Anwendung nicht tun sollte. Aus dieser Sicht liegt die Schwachstelle in der Anwendung, nicht im Interpreter. Bei zwei ähnlichen Fehlern, CVE-2022-28738 und CVE-2024-27282, hat Ruby nach Prüfung trotzdem CVEs vergeben, und die Dokumentation sagt bis heute nicht klar, ob der Anwendungsfall unterstützt wird. Das Team will das nun klären und dann über CVEs entscheiden.
Für Betreiber hat das eine praktische Folge. Die vier GitLab-CVEs beschreiben GitLab-Versionen, nicht Ruby-Versionen. Werkzeuge, die installierte Software gegen CVE-Datenbanken abgleichen, finden zu einem alten Ruby 3.4.11 deshalb keinen Eintrag und schlagen nicht an. Wer betroffen ist, erfährt es nur aus dem Ruby-Advisory. Bis zu einer Entscheidung empfiehlt das Team, die GitLab-Kennungen zur Nachverfolgung zu nutzen.
KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.