FlawOpen

flawopen.com/Incidents/gitlab-commits-api-path-traversal-september-2026

● GitLab · CVE-2026-85706 · September 2026 · CVSS 10.0 · Kritisch
Sicherheitsforschung · FlawOpen

CVE-2026-85706: GitLab-Dateioffenlegung

GitLabs Upload-Parser konnte ohne Anmeldung Serverdateien auswählen; fehlerhafte Escapes zeigten Fragmente in Fehlermeldungen.[1], [3]

CVSS-VektorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N[3]
💡 Einfache Erklärung (ELI5)

Stellen Sie sich einen Empfangsmitarbeiter vor, der statt des Dokuments im Eingangsfach eine vom Besucher notierte Schranknummer annimmt. Noch vor der Ausweiskontrolle öffnet er den Schrank. Kann er eine Zeile nicht lesen, zitiert er sie laut in der Fehlermeldung. Das Öffnen ist ein Fehler, das Vorlesen ein zweiter.[1]

Kernkonzepte & Begriffe

Upload metadata
Vom Client gelieferte file.path- oder metadata.path-Werte dürfen einen vom vertrauenswürdigen Upload-System registrierten Puffer nicht ersetzen.[1]
Percent decoding
Bei Formulardaten wird % mit zwei Hexadezimalziffern dekodiert; eine ungültige Folge kann einen Fehler mit dem betroffenen Fragment erzeugen.[1]
CWE-22 / CVSS
Die CNA stuft CVE-2026-85706 als Pfad-Traversal mit CVSS 10.0 Kritisch ein. Überschritten wird die Grenze zur clientgesteuerten Auswahl von Serverdateien.[3]

Framework-Zuordnungen

Vorfall-Zeitstrahl

2026-09-10

GitLab veröffentlichte die Korrekturen 19.1.8, 19.2.6 und 19.3.2.[2]

2026-09-23

Die Versionsmitteilung ergänzte Rückportierungen für 18.11.12 und 19.0.9.[2]

Schritt-für-Schritt Angriffsablauf

Schritt 1

Auswahl vor Anmeldung

Upload-Metadaten konnten den erwarteten temporären Puffer noch vor der Authentifizierung durch einen Serverpfad ersetzen.[1]

Schritt 2

Datei als Formular behandelt

Bei application/x-www-form-urlencoded wurde die ausgewählte Datei als Formulardaten verarbeitet, statt als normale Commit-Antwort zurückgegeben zu werden.[1]

Schritt 3

Fragment im Fehler

Ungültige Prozentkodierung konnte das fehlerhafte Fragment in eine Fehlermeldung übernehmen. & und = begrenzten dessen Umfang; ein Lesevorgang allein beweist keine Offenlegung.[1]

Schritt 4

Untersuchung

Verknüpfen Sie Einträge der Rails-API und von Workhorse über correlation_id; vergleichen Sie api_error mit written_bytes, um festzustellen, ob Antwortdaten gesendet wurden.[1]

Quellcode: Verwundbar vs. Sicher

Anschauliches Python-Modell, weder GitLab-Quellcode noch dessen Patch. Das fehlerhafte Beispiel nutzt nur Speicherpuffer und behandelt jedes % als Fehler; echte Prozentprüfung und Fragmentgrenzen werden nicht nachgebildet. Das verbesserte Modell authentifiziert zuerst, verweigert Pfadmetadaten, nimmt nur Bytes aus dem vertrauenswürdigen Upload-System an, begrenzt die Größe und liefert allgemeine Fehler. Installieren Sie das Herstellerupdate: Prüfung innerhalb einer Route kommt zu spät, wenn frühere Middleware die Datei bereits gelesen hat.[1]

VERWUNDBARE IMPLEMENTIERUNG
from urllib.parse import unquote_to_bytes

def parse_upload(authenticated, metadata, buffers):
    # Harmlose In-Memory-Fixtures; kein Dateisystemzugriff.
    body = buffers.get(metadata.get("path"), b"")
    if b"%" in body:
        return 400, body.decode("ascii", errors="replace")
    if not authenticated:
        return 401, "Unauthorized"
    return 200, unquote_to_bytes(body)
GEHÄRTETER SICHERHEITS-PATCH
from urllib.parse import unquote_to_bytes

MAX_BYTES = 4096
HEX = frozenset(b"0123456789abcdefABCDEF")

def parse_upload(authenticated, metadata, registered_body):
    # registered_body stammt aus vertrauenswürdiger Upload-Middleware,
    # niemals aus einem durch Anfrageparameter gewählten Pfad.
    if not authenticated:
        return 401, "Unauthorized"
    if metadata or type(registered_body) is not bytes:
        return 400, "Invalid upload"
    if len(registered_body) > MAX_BYTES:
        return 413, "Upload too large"
    for i, byte in enumerate(registered_body):
        if byte == 37 and (i + 2 >= len(registered_body) or
                registered_body[i+1] not in HEX or
                registered_body[i+2] not in HEX):
            return 400, "Invalid upload"
    return 200, unquote_to_bytes(registered_body)

Checkliste für Engineering & Systemsicherheit

Quellen