Apa inti CVE-2024-6886 dan versi Gitea mana yang terdampak serta yang menambalnya?
Apa akar penyebab (root cause) kerentanan stored XSS ini?
Bagaimana cara menemukannya secara manual, dengan SAST, dan dengan DAST?
Apa dampaknya dan bagaimana Gitea memperbaikinya?
Mengapa tidak ada satu tool tunggal yang menangkap semua bug?
Reference Points
IF4053 Keamanan Perangkat Lunak (W12 — CVE-2024-6886 Stored XSS Walkthrough)
IF4053 Keamanan Perangkat Lunak (W12 — bagian “Coverage Matrix & How It Was Fixed”)
CVE at a Glance
CVE-2024-6886 adalah kerentanan Stored Cross-Site Scripting (CWE-79) pada Gitea 1.22.0, ditambal pada Gitea 1.22.1. Severity-nya CVSS 3.1 = 6.7 (Medium). Vektor serangannya adalah field Description repository. Kerentanan ini membutuhkan autentikasi—dapat dipicu oleh pengguna mana pun yang memiliki hak edit repository. Karena payload disimpan di deskripsi, setiap pengunjung halaman repo (terutama repo publik) menjadi korban potensial. Sumber resmi: github.com/advisories/GHSA-4h4p-553m-46qh. Catatan etis: walkthrough ini hanya untuk tujuan edukasi—uji hanya pada container Docker milik sendiri.
Akar Penyebab — Titik Buta Sanitizer
Gitea memakai sanitizer Bluemonday yang mengizinkan tag <a> agar pengguna dapat menaruh tautan di deskripsi repo. Namun pada 1.22.0, ketika tidak ada daftar skema kustom yang dikonfigurasi (setting.Markdown.CustomURLSchemes == nil), kebijakan memanggil policy.AllowURLSchemesMatching(allowAllRegex) yang mengizinkan SEMUA skema URL—termasuk javascript:, vbscript:, dan data:. Akibatnya penyerang dapat menyisipkan tautan yang dapat diklik dan mengeksekusi JavaScript. Inti masalahnya: default sanitizer yang terlalu permisif.
Langkah pertama menjalankan versi rentan: docker run -d --name gitea -p 3000:3000 -p 222:22 docker.gitea.com/gitea:1.22.0, selesaikan setup wizard, buat admin, lalu buat repo uji. Penemuan manual via UI: buka repo → Settings → field Description, tempel payload <a href=javascript:alert('XSS-CVE-2024-6886')>Click me for XSS</a>, klik Update Settings, kembali ke halaman repo, lalu klik tautan yang ter-render—JavaScript dieksekusi di sesi browser. Penemuan via intercepting proxy (Burp/ZAP): tangkap POST /{user}/{repo}/settings di HTTP History, kirim ke Repeater (Burp) atau Manual Request Editor (ZAP), ganti deskripsi dengan payload ter-URL-encode %3Ca+href%3Djavascript%3Aalert(1)%3Ex%3C%2Fa%3E, kirim, muat repo, klik tautan—alert muncul, kerentanan terkonfirmasi. Serangan nyata akan mencuri cookie, membajak sesi, atau menambahkan SSH key via API.
flowchart TD
A["Penyerang: tanam payload di Description"] --> B["Gitea simpan tanpa sanitasi skema"]
B --> C["Korban buka halaman repo"]
C --> D["Klik tautan javascript:"]
D --> E["JS dieksekusi: curi cookie/sesi"]
Penemuan dengan SAST
SAST (Static Application Security Testing) memeriksa kode sumber tanpa menjalankannya. Untuk CVE ini, rule Semgrep kustom dapat menandai pola konfigurasi sanitizer yang tidak aman dengan pattern $POLICY.AllowURLSchemesMatching($REGEX) (severity ERROR, language Go), dijalankan via semgrep --config=ci-rules/ modules/markup/. SAST menangkap: pemanggilan library berbahaya (AllowURLSchemesMatching), pola sink langsung (innerHTML, eval), kredensial hardcoded, dan dependensi Go usang. SAST melewatkan: bug yang bergantung pada konteks runtime, cacat logika (autentikasi, permission), keanehan parser browser, dan rantai serangan multi-langkah. SAST unggul pada bug berbasis pola, lemah pada logika dan perilaku.
Penemuan dengan DAST
DAST (Dynamic Application Security Testing) menguji aplikasi yang sedang berjalan—mengirim HTTP request nyata dan mengamati respons. Active Scanner ZAP dapat mendeteksi stored XSS ini secara otomatis, misalnya via Docker one-shot: zap-full-scan.py -t http://localhost:3000 -r xss-scan.html, lalu cari alert ‘Cross Site Scripting (Persistent)‘. Penting: ZAP membutuhkan sesi terautentikasi untuk mencapai form deskripsi—gunakan konteks Authentication-nya. DAST menangkap: reflected dan stored XSS, SQL/command injection, security header yang hilang, cookie yang salah konfigurasi. DAST melewatkan: bug di balik tembok autentikasi, endpoint yang tidak ditemukan crawler, cacat business logic, serta race condition.
Coverage Matrix, Dampak, dan Mitigasi
Coverage Matrix menunjukkan tidak ada tool tunggal yang menangkap semuanya: pengujian manual di browser (✓, effort rendah), Burp Repeater (✓, rendah), Semgrep default (⚠ mungkin), Semgrep rule kustom (✓, medium), gosec (✗), ZAP baseline pasif (✗), ZAP full active scan (✓, medium), dan Trivy image scan (✓ via versi, rendah). Dampak: pencurian cookie/sesi, pembajakan akun, hingga penambahan SSH key—diperparah pada repo publik. Mitigasi (Gitea 1.22.1): beralih dari regex allowlist yang luas ke daftar skema aman eksplisit—policy.AllowURLSchemes("http", "https", "mailto", "ftp")—sehingga javascript:/vbscript:/data: tak lagi lolos bahkan bila konfigurasi hilang. Prinsipnya: allowlist mengalahkan denylist (enumerasi yang aman, bukan yang berbahaya).
Summary
CVE-2024-6886 adalah stored XSS (CWE-79) pada Gitea 1.22.0 (ditambal di 1.22.1, CVSS 6.7 Medium) melalui field Description repository, dipicu pengguna ber-hak edit. Akar penyebabnya: sanitizer Bluemonday dengan default AllowURLSchemesMatching(allowAllRegex) yang meloloskan skema javascript:. Penemuan manual dengan menanam payload <a href=javascript:...> lewat UI atau Burp/ZAP Repeater; SAST lewat rule Semgrep kustom yang menandai AllowURLSchemesMatching; DAST lewat ZAP Active Scanner (perlu sesi terautentikasi). Tidak ada satu tool yang menangkap semua—Trivy bahkan mendeteksi via versi. Perbaikannya mengganti regex luas dengan allowlist skema aman eksplisit, menegaskan prinsip allowlist beats denylist.
Additional Information
Lebih dalam — Mengapa Stored XSS Lebih Berbahaya dari Reflected (DI LUAR sumber)
Pada reflected XSS, payload harus dikirim ke korban setiap kali (mis. via tautan phishing) dan hanya aktif saat korban mengklik tautan jahat tersebut. Stored XSS menyimpan payload di server (di sini, field deskripsi), sehingga setiap pengunjung halaman otomatis terkena tanpa interaksi tambahan—penyebarannya pasif dan persisten. Field metadata seperti deskripsi, bio, dan judul adalah pola berulang untuk stored XSS karena sering dianggap “hanya teks” dan luput dari sanitasi ketat.
Lebih dalam — Content Security Policy sebagai Lapis Pertahanan (DI LUAR sumber)
Selain sanitasi input, Content Security Policy (CSP) dapat memitigasi XSS di sisi browser. Header Content-Security-Policy: script-src 'self' mencegah eksekusi skema javascript: inline dan script dari domain asing meski payload lolos sanitasi. CSP adalah defense in depth—bukan pengganti sanitasi, melainkan jaring pengaman bila sanitasi gagal.
Proyek Eksplorasi Mandiri
Jalankan Gitea 1.22.0 dan 1.22.1 berdampingan di dua container, reproduksi payload pada keduanya, lalu bandingkan perilaku render untuk membuktikan efektivitas patch.
Tulis dan jalankan rule Semgrep kustom dari slide terhadap source Gitea 1.22.0 dan 1.22.1; verifikasi bahwa rule menyala hanya pada versi rentan.
Jalankan Trivy terhadap image gitea:1.22.0 dan amati apakah CVE-2024-6886 muncul hanya dari pemeriksaan versi.
Bacaan Lanjutan
GitHub Advisory GHSA-4h4p-553m-46qh dan diff commit Gitea v1.22.0 ↔ v1.22.1.
Dokumentasi bluemonday (kebijakan sanitasi HTML untuk Go) dan OWASP XSS Prevention Cheat Sheet.
OWASP Content Security Policy Cheat Sheet untuk mitigasi lapis browser.