FlawOpen

flawopen.com/Teardowns/cve-2026-87902-wordpress-page-template-path-traversal

● CVE-2026-87902 · CVSS 9.2[1] · Kritis
Riset Keamanan · FlawOpen

CVE-2026-87902: Path traversal pada template halaman WordPress

Nama halaman hasil dekode yang tidak divalidasi masuk ke resolusi template, sehingga PHP lokal dapat disertakan tanpa autentikasi. RCE memerlukan kondisi tema dan PHP tertentu.[1]

💡 Penjelasan Sederhana (ELI5)

Bayangkan pustakawan yang memeriksa permintaan sebelum mengambil buku. WordPress memeriksa satu jalur ke daftar template, tetapi melewatkan jalur dari nama yang sudah didekode. Penanda khusus dapat membawanya keluar dari direktori tema. Perbaikan memvalidasi nama dan menjaga template dalam direktori yang diizinkan.[1], [2], [3]

Konsep Kunci & Istilah

Resolusi template halaman
WordPress mengurutkan kandidat PHP dan mencari file pertama yang cocok di tema aktif.[1], [2]
Path traversal
Komponen seperti .. dapat keluar dari direktori tujuan jika input tidak divalidasi.[1]
Penyertaan PHP lokal
Memuat file PHP yang sudah ada di server; RCE memerlukan kondisi tambahan.[1]
`validate_file()`
Fungsi WordPress yang menolak komponen jalur terlarang sebelum digunakan.[3]
CWE-98
CWE-98 — Pengendalian nama berkas include/require yang tidak tepat: masukan tidak cukup dibatasi sebelum memilih berkas PHP.[1], [7]

Pemetaan kerangka kerja

Analisis Akar Masalah (Root Cause)

Di get_page_template(), WordPress mendekode pagename lalu menambahkan page-{name}.php tanpa validate_file(), sementara cabang di sebelahnya melakukan pemeriksaan tersebut. Jalur dapat keluar dari tema. Diperlukan direktori tingkat atas page-* dan PHP lokal yang dapat dibaca; RCE juga memerlukan kondisi PHP/server tambahan. Versi 7.1.2 memvalidasi nilai hasil dekode dan membatasi jalur di locate_template(). Advisori WordPress mengklasifikasikan kelemahan ini sebagai CWE-98 (pengendalian nama berkas yang tidak tepat pada PHP include/require) dan mencantumkan Robert Ressl sebagai penemu serta pihak yang mengungkapkannya secara bertanggung jawab.[1], [2], [3], [7]

Cakupan CVE-2026-87902: kondisi paparan dan RCE bersyarat

Kondisi deploymentHal yang dibuktikan sumber primerTindakan operator
Cabang WordPress Core yang terdampakGHSA mencantumkan versi terdampak per cabang, dari 4.7.0–4.7.36 hingga 7.1.0–7.1.1. Versi perbaikannya berkisar dari 4.7.37 (backport paling awal) hingga 7.1.2 (cabang saat ini); setiap cabang yang tercantum memiliki rilis perbaikan tersendiri.Periksa versi Core yang terpasang dan terapkan perbaikan untuk cabang tersebut. Tingkatkan versi sebelum 4.7 ke rilis yang masih didukung.
Struktur tema aktifTema parent atau child yang aktif harus memiliki direktori tingkat teratas dengan nama yang diawali page- (misalnya page-templates).Periksa direktori kedua tema aktif. Periksa ulang kondisi ini saat tema aktif berubah.
Berkas PHP lokal yang dapat dibacaBerkas .php yang dipilih harus ada di luar direktori tema aktif dan dapat dibaca oleh akun server web.Periksa berkas PHP lokal yang dapat dibaca server web; rentang versi CVE saja tidak membuktikan bahwa berkas telah disertakan.
Lingkungan RCE bersyaratAdvisory menjelaskan RCE hanya jika syarat PHP/server tambahan terpenuhi. Contohnya pearcmd.php saat register_argc_argv=On, image PHP Docker resmi, dan konfigurasi default cPanel dengan PHP sebelum 8.5.Nilai runtime dan konfigurasi PHP yang sebenarnya. Versi WordPress yang terdampak saja tidak membuktikan RCE atau kompromi.

Alur Serangan Langkah demi Langkah

Langkah 1

Input masuk ke pemilihan template

Permintaan tanpa autentikasi menyediakan nama untuk membuat kandidat; akun dan klik tidak diperlukan.[1]

Langkah 2

Dekode ulang

get_page_template() mendekode nama lagi; versi terdampak tidak memvalidasi kandidat hasil dekode.[2], [3]

Langkah 3

Pencarian keluar dari akar

Dengan direktori page-* dan PHP lokal yang dapat dibaca, tema dapat menyelesaikan file di luar direktorinya.[1]

Langkah 4

Dampak bersyarat

RCE membutuhkan kondisi PHP/server tambahan; versi saja tidak membuktikan eksploitabilitas atau kompromi.[1]

Kode Sumber: Rentan vs Aman

Cuplikan ini membandingkan tag sumber resmi 7.1.1 dan 7.1.2. Patch memvalidasi nilai setelah dekode; rilis yang sama juga membatasi jalur hasil resolusi di locate_template(). Ini perubahan sumber upstream, bukan patch mandiri lengkap atau demonstrasi eksploitasi.[2], [3]

Cuplikan sumber: wp-includes/template.php — get_page_template()

IMPLEMENTASI RENTAN
if ( $pagename ) {
    $pagename_decoded = urldecode( $pagename );

    if ( $pagename_decoded !== $pagename ) {
        $templates[] = "page-{$pagename_decoded}.php";
    }
}
PERBAIKAN AMAN & KUAT
if ( $pagename ) {
    $pagename_decoded = urldecode( $pagename );

    if ( $pagename_decoded !== $pagename && 0 === validate_file( $pagename_decoded ) ) {
        $templates[] = "page-{$pagename_decoded}.php";
    }
}

Daftar Periksa Penguatan Sistem Rekayasa

Sumber