FlawOpen

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

● GitLab · CVE-2026-85706 · September 2026 · CVSS 10.0 · Kritis
Riset Keamanan · FlawOpen

CVE-2026-85706: pengungkapan berkas server GitLab

Parser unggahan GitLab memilih berkas server tanpa autentikasi; escape keliru menampilkan cuplikan di galat, tetapi pemilihan tak membocorkan isinya.[1], [3]

Vektor CVSSCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N[3]
💡 Penjelasan Sederhana (ELI5)

Bayangkan petugas penerimaan mengikuti lokasi lemari yang ditulis pengunjung, bukan dokumen di baki masuk. Sebelum memeriksa kartu identitas, ia membuka lemari itu; bila satu baris sulit dibaca, ia membacakannya dalam pesan galat. Membuka dokumen adalah satu kesalahan, membacakan isinya adalah kesalahan lain.[1]

Konsep Kunci & Istilah

Upload metadata
file.path atau metadata.path dari permintaan tidak boleh menggantikan penyangga yang didaftarkan oleh pemroses unggahan tepercaya.[1]
Percent decoding
Dalam penguraian formulir, % diikuti dua digit heksadesimal akan didekode; urutan tidak valid dapat memunculkan galat yang memuat potongan bermasalah.[1]
CWE-22 / CVSS
CNA menggolongkan CVE-2026-85706 sebagai penelusuran lintas jalur, CVSS 10.0 Kritis. Batas yang dilanggar ialah pemilihan berkas server oleh peminta.[3]

Pemetaan kerangka kerja

Kronologi Insiden

2026-09-10

GitLab merilis perbaikan 19.1.8, 19.2.6, dan 19.3.2.[2]

2026-09-23

Pengumuman diperbarui untuk mencakup perbaikan pada 18.11.12 dan 19.0.9.[2]

Alur Serangan Langkah demi Langkah

Langkah 1

Pemilihan sebelum autentikasi

Metadata unggahan dapat menggantikan penyangga sementara yang diharapkan dengan jalur server sebelum autentikasi.[1]

Langkah 2

Isi menjadi parameter

Dengan application/x-www-form-urlencoded, berkas terpilih ditafsirkan sebagai data formulir, bukan dikirim sebagai jawaban commit biasa.[1]

Langkah 3

Pantulan dalam galat

Escape persen yang tidak valid dapat memasukkan potongan yang gagal ke galat. Pemisah & dan = menentukan cakupannya; pembacaan saja tidak membuktikan kebocoran.[1]

Langkah 4

Penyelidikan

Cocokkan entri Rails API dan Workhorse melalui correlation_id; bandingkan api_error dengan written_bytes untuk menilai apakah byte terkirim dalam respons.[1]

Kode Sumber: Rentan vs Aman

Model Python untuk belajar, bukan sumber atau tambalan GitLab. Contoh rentan hanya memakai penyangga di memori dan menganggap setiap % sebagai galat; validasi nyata dan pemilihan potongan tidak ditiru. Model yang diperkuat mengautentikasi lebih dulu, menolak metadata jalur, menerima hanya byte dari sistem unggahan tepercaya, membatasi ukuran, dan mengembalikan galat umum. Pasang pembaruan vendor: autentikasi di rute terlambat jika lapisan sebelumnya sudah membaca berkas.[1]

IMPLEMENTASI RENTAN
from urllib.parse import unquote_to_bytes

def parse_upload(authenticated, metadata, buffers):
    # Aman di memori; tidak mengakses sistem berkas.
    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)
PERBAIKAN AMAN & KUAT
from urllib.parse import unquote_to_bytes

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

def parse_upload(authenticated, metadata, registered_body):
    # registered_body berasal dari middleware unggahan tepercaya,
    # bukan dari jalur yang dipilih melalui parameter permintaan.
    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)

Daftar Periksa Penguatan Sistem Rekayasa

Sumber