Skor 9,2 yang perlu dibaca dengan teliti
WordPress 7.1.2 dirilis pada 22 September 2026 untuk menambal celah pada cara core memilih template halaman. Menurut catatan rilisnya, penyerang tanpa autentikasi, dalam kondisi tertentu, bisa membuat proses resolusi template halaman memuat file PHP lokal pilihannya, asalkan file itu bisa dibaca, dari luar direktori tema yang aktif. Perbaikannya di-backport ke semua cabang yang masih menerima rilis keamanan, dan saat ini itu berarti semua versi sampai 4.7.
Advisory-nya, GHSA-7hp8-65ch-5whp / CVE-2026-87902, memberinya peringkat Critical dengan skor CVSS 4.0 sebesar 9,2. Versi yang terdampak adalah 4.7.0 sampai 7.1.1. Robert Ressl menemukan bug ini dan melaporkannya secara privat pada 20 Juli. Patch, advisory, dan repositori proof-of-concept miliknya dipublikasikan pada hari yang sama. Menurut Patchstack, upaya probing dimulai kurang dari lima jam kemudian.
Ada dua hal yang sama-sama benar. Hampir satu dekade rilis WordPress terdampak, dan serangannya tidak butuh login. Tapi mengubah bug ini menjadi remote code execution (RCE) butuh kondisi yang tidak dipenuhi banyak situs. Beberapa judul berita sudah menyebutnya "sudah dieksploitasi". Sejauh ini, bukti yang ada baru menunjukkan pengintaian, tidak lebih. Anda tidak perlu panik. Yang perlu Anda lakukan, pagi ini juga, adalah memastikan situs Anda termasuk golongan yang mana. Itulah yang dibahas tulisan ini.
Mengapa bug ini jadi RCE di sebagian host, tapi tidak di yang lain
Analisis akar masalah dari Patchstack menelusuri bug ini sampai ke get_page_template() di wp-includes/template.php. Fungsi itu menyusun nama file kandidat, page-{$pagename}.php, dari query variable pagename. Cabang di sebelahnya melewatkan input lewat validate_file(). Cabang pagename tidak, sehingga sekuens traversal yang di-encode dua kali bisa lolos. Patchstack merangkum cakupannya: setiap cabang sampai 4.7 terdampak, artinya hampir satu dekade rilis, dan penyerang tidak butuh akun apa pun.
Kalau berdiri sendiri, ini baru local file include (LFI). Advisory-nya mencantumkan dua prasyarat tambahan yang mengubahnya menjadi eksekusi kode:
- Tema aktif punya direktori tingkat atas yang namanya diawali
page-. Advisory menyebut Twenty Twelve, Twenty Fourteen, Neve, Hestia, dan Sydney. Dalam tulisannya, Ressl mencatat bahwa tema default saat ini (Twenty Twenty-Three, Twenty Twenty-Four, dan Twenty Twenty-Five) tidak punya direktori seperti itu. - Server punya file
.phpyang bisa dibaca dan bisa disalahgunakan begitu dimuat. Contoh dari advisory adalahpearcmd.phpmilik PEAR denganregister_argc_argvaktif. Setelan itu aktif secara default di image Docker PHP resmi dan di lingkungan cPanel.
Prasyarat kedua inilah yang membuat bug ini lebih serius bagi setup self-hosted dan berbasis container daripada kesan "hanya tema lama" yang beredar. Banyak WordPress berjalan di atas image PHP resmi, sering kali dari Dockerfile yang ditulis seseorang bertahun-tahun lalu dan tidak pernah dibuka lagi. Ressl sendiri berhati-hati soal ini: apakah setiap instalasi default bisa dieksploitasi? Menurutnya, bukti yang ada belum menunjukkan hal itu. Jadikan itu alasan untuk mengecek, bukan alasan untuk bersantai.
Empat pengecekan: apakah Anda terpapar?
Jalankan perintah-perintah ini dari root WordPress, atau di dalam container. Masing-masing menjawab satu pertanyaan.
1. Apakah Anda sudah di versi yang diperbaiki, dan akan tetap di sana?
wp core version
Rilis yang sudah diperbaiki adalah 7.1.2, 7.0.6, 6.9.9, dan 6.8.10, dengan backport untuk cabang lama sampai 4.7.37. Semua versi mulai 4.7.0 sampai sebelum rilis perbaikan di cabang Anda masih rentan. The Hacker News mencatat bahwa situs dengan pembaruan otomatis di latar belakang akan menerima patch tanpa perlu ada yang turun tangan. Tapi jangan langsung berasumsi situs Anda termasuk di antaranya. Instalasi berbasis container sering kali menanam core langsung di dalam image. Filesystem read-only memblokir pembaruan, dan membuat ulang container dari image lama akan mengembalikannya ke versi rentan. Kalau versi Anda masih masuk daftar rentan sehari setelah rilis, berarti pembaruan otomatis tidak berjalan untuk Anda.
2. Apakah tema aktif punya direktori page-*?
wp theme list --fields=name,status
ls -d wp-content/themes/*/page-*/ 2>/dev/null
Bandingkan kedua output-nya. Jika tema aktif, atau tema induknya kalau Anda memakai child theme, muncul di daftar kedua, Anda memenuhi prasyarat pertama. Tema-tema yang disebut advisory hanyalah titik awal, bukan daftar lengkap. Tema komersial dan tema buatan sendiri yang mengelompokkan template halaman ke dalam folder juga bisa cocok.
3. Apakah register_argc_argv aktif untuk request web?
Jangan cek ini dengan php -i di command line. SAPI CLI selalu memaksa register_argc_argv aktif, apa pun isi php.ini Anda, jadi jawabannya pasti "on" dan sama sekali tidak informatif. Tanyakan langsung ke SAPI web, lalu segera hapus file-nya:
echo '<?php echo ini_get("register_argc_argv") ? "on" : "off";' > argc-check-7f3a.php
curl -s https://situs-anda.example/argc-check-7f3a.php; echo
rm argc-check-7f3a.php
Kalau hasilnya on dan Anda tidak membutuhkannya, matikan. Di image Docker resmi, cara tercepat adalah memakai php.ini-production yang sudah disertakan di image tersebut, karena file itu mematikan setelan ini. Pilihan lainnya adalah override eksplisit:
RUN cp "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& echo 'register_argc_argv = Off' > "$PHP_INI_DIR/conf.d/zz-argc.ini"
4. Apakah pearcmd.php ada di server?
find / -name pearcmd.php -not -path '/proc/*' 2>/dev/null
Karena include-nya bersifat lokal, yang penting adalah apakah proses PHP bisa membaca file itu, bukan apakah file itu bisa diakses dari web. Kalau PEAR terpasang dan tidak ada yang memakainya, hapus saja. PEAR memang gadget yang disebut dalam rantai serangan ini, tapi kemungkinan besar bukan satu-satunya. Karena itulah saran Ressl juga mencakup pembatasan apa saja yang boleh dibaca dan ditulis oleh user PHP.
Jika pengecekan pertama menunjukkan Anda sudah di-patch, Anda aman dari CVE ini. Tiga pengecekan lainnya tetap penting, karena ketiganya menunjukkan seberapa parah dampak bug file include berikutnya.
Apakah situs Anda sudah di-probe?
Patchstack mendeteksi probe pertama pada pukul 17.44 UTC tanggal 22 September. Request-request itu menyisipkan traversal yang di-encode dua kali di pagename bersama page_id yang valid, dan sebagian besar memakai user agent Go-http-client/1.1. Sasarannya adalah file core yang tidak berbahaya seperti wp-links-opml.php. Itu tanda ada yang sedang menguji apakah include-nya berhasil, belum mencoba menjalankan apa pun. Patchstack belum mengonfirmasi adanya eksekusi payload yang berhasil.
Mulailah dengan pencarian yang luas. Perintah ini menangkap dot-dot yang di-encode dua kali di bagian mana pun dari baris request, baik di log saat ini maupun log yang sudah dirotasi:
zgrep -i '%252e%252e' /var/log/nginx/access.log*
Lalu persempit ke pola persis yang dijelaskan Patchstack:
zgrep -iE 'pagename=[^ &]*%252e%252e' /var/log/nginx/access.log* \
| grep -i 'Go-http-client/1.1'
Sesuaikan path-nya untuk Apache atau log shipper yang Anda pakai. Patchstack juga menyarankan menelusuri log lama untuk mencari output OPML yang dikembalikan dari URL halaman biasa. Dalam praktiknya, itu berarti mencari request halaman yang ukuran respons atau content type-nya cocok dengan wp-links-opml.php, bukan dengan HTML tema Anda.
Selama masih ada situs yang belum di-patch, blokir traversal di pagename di level edge. Patchstack dan Hadrian sama-sama merekomendasikan langkah ini. Versi nginx yang kasar tapi efektif:
if ($args ~* "pagename=[^&]*(\.\.|%2e|%25)") {
return 403;
}
Hadrian berhasil mereproduksi include tersebut di instalasi 7.1.1 yang terisolasi. Hadrian juga merilis template Nuclei yang mengirim tiga request tanpa autentikasi lalu membandingkan body responsnya. Ini cara cepat untuk menguji banyak situs sekaligus dari luar.
Kelas bug-nya: decode, lalu validasi, lalu batasi
Sebenarnya ini bukan kesalahan yang khas WordPress. Kode apa pun yang menyusun path file dari input request bisa terjebak di lubang yang sama, lewat dua cara.
Yang pertama adalah memvalidasi sebelum decode terakhir. %252e lolos dari pengecekan .. maupun %2e. String itu baru menjadi %2e, lalu ., setelah di-decode lagi oleh lapisan berikutnya. Kalau pengecekan Anda berjalan sebelum nilainya mencapai bentuk akhir, yang Anda periksa adalah string yang salah.
Yang kedua adalah menyamakan kanonikalisasi dengan pembatasan (containment). realpath() memberi tahu ke mana sebuah path sebenarnya mengarah. Fungsi itu tidak memberi tahu apakah lokasi tersebut diizinkan. Containment adalah perbandingan terpisah terhadap direktori dasar, dan separator di ujungnya ikut menentukan. Tanpa separator itu, /themes/foo juga akan cocok dengan /themes/foo-evil.
Berikut pola lengkapnya dalam kode:
function safe_template_path(string $baseDir, string $input): ?string
{
// Decode sekali; kalau masih bisa di-decode lagi, berarti di-encode berlapis. Tolak, jangan diulang.
$decoded = rawurldecode($input);
if ($decoded !== rawurldecode($decoded)) {
return null;
}
// Allowlist bentuk yang sah, alih-alih blocklist sekuens berbahaya.
if (!preg_match('/^[a-z0-9-]+$/', $decoded)) {
return null;
}
// Kanonikalisasi, lalu batasi: bandingkan dengan direktori dasar plus separator di ujungnya.
$base = rtrim(realpath($baseDir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
$path = realpath($base . 'page-' . $decoded . '.php');
if ($path === false || !str_starts_with($path, $base)) {
return null;
}
return $path;
}
Allowlist itulah yang melakukan sebagian besar pekerjaan. Slug halaman tidak punya alasan untuk mengandung titik, garis miring, atau tanda persen, jadi tolak ketiganya sebelum kode Anda menyentuh filesystem sama sekali.
Yang perlu dilakukan pagi ini
- Perbarui, lalu cek
wp core versiondi setiap instalasi. Jangan percaya begitu saja bahwa pembaruan otomatis sudah berjalan, terutama di container dan image yang versinya dikunci. - Matikan
register_argc_argvuntuk request web di mana pun Anda tidak membutuhkannya, dan mulai build Docker dariphp.ini-production. - Hapus entry point PEAR yang tidak terpakai dan perketat akses baca-tulis filesystem untuk akun PHP, sesuai saran Ressl.
- Grep log Anda untuk
%252e%252e, dan pasang aturan edge sementara yang memblokir traversal dipagenameuntuk situs mana pun yang belum bisa Anda patch hari ini. - Audit kode Anda sendiri untuk pola yang sama: setiap path yang disusun dari input request butuh decode penuh, allowlist, dan pengecekan containment, dengan urutan persis seperti itu.
Skor CVSS memberi tahu seberapa parah hal ini bisa terjadi. Empat pengecekan tadi memberi tahu seberapa parah kondisinya di server Anda.




Komentar (0)
Belum ada komentar. Mulai percakapannya.