Jawaban langsung: PHP2Shell adalah nama julukan untuk 2 celah kritis di mesin PHP: CVE-2026-109618 dan CVE-2026-109619. Keduanya dapat membuka eksekusi kode dari jarak jauh (RCE) tanpa login, dengan skor CVSS v4.0 9.2. Update PHP ke 8.5.12, 8.4.27, 8.3.36, atau 8.2.35 malam ini, lalu restart semua worker PHP.

Celah ini ada di mesin PHP, bukan di kode aplikasi Anda. Jadi WordPress, Laravel, atau toko online yang kodenya bersih tetap terdampak bila versi PHP di server lama.

Kondisi utama: Risiko berlaku untuk semua instalasi PHP yang melayani request web: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, dan LiteSpeed. advisory keamanan php.net menilai mod_php paling berisiko. Batas: Mitigasi sementara di artikel ini hanya mengurangi paparan. Mitigasi itu tidak membuat server aman. Artikel ini juga tidak memuat kode eksploit.

Kami membaca advisory keamanan php.net, advisory GHSA-w8hw-w9fx-j79w dan GHSA-6wmf-4rv5-p3rp, NVD, CVE.org, Ubuntu USN-8948-1, riset Sansec, tulisan Huntress, FAQ watchTowr, dan brief Unit 42 Palo Alto Networks pada 21 Oktober 2026, sekitar pukul 22.00 WIB. Perintah di langkah 1, 2, dan 4 kami jalankan di container uji pada tanggal yang sama. Status paket bisa berubah dalam hitungan jam, jadi ulangi langkah 2 sebelum Anda memutuskan.

Masalah: celah bocor dulu, patch datang sesudahnya

Detail celah bocor pada 20 Oktober 2026, dan serangan awal muncul sebelum patch terbit. Jangan tunggu jadwal maintenance.

Biasanya, patch terbit dulu dan detail celah menyusul. Kali ini urutannya terbalik. Pada pagi 20 Oktober 2026, sebuah posting di Hacker News mengumumkan 2 celah kritis PHP, lalu dihapus. tulisan Huntress mencatat bahwa watchTowr mengonfirmasi kebocoran itu dalam beberapa jam.

Tim PHP lalu memajukan rilis 1 hari dari jadwal embargo. Menurut riset Sansec, Cloudflare melaporkan serangan awal ke situs PHP pada 21 Oktober pukul 14.43 WIB, sebelum patch terbit. FAQ watchTowr melaporkan eksploitasi di jaringan honeypot mereka pada hari yang sama.

Skalanya besar. brief Unit 42 Palo Alto Networks menulis bahwa Cortex Xpanse menemukan lebih dari 22,6 juta instance yang terekspos dan berpotensi rentan. riset Sansec menyebut uji Calif menembus WordPress 7.1.2, Laravel 13.11, Magento 2.4.9, Drupal 11.4.3, phpMyAdmin 5.2.3, dan Nextcloud 35.0.1 tanpa login.

Linimasa dari 2004 sampai 21 Oktober 2026: laporan Calif dan Wiz pada Agustus, kebocoran 20 Oktober, serangan awal yang dilaporkan Cloudflare, rilis patch, dan eksploitasi di honeypot watchTowr.
Titik abu-abu: riwayat masalah memori PHP sejak 2004. Titik merah: 4 kejadian dalam 2 hari terakhir. Serangan awal tercatat sebelum patch terbit.

Pekan lalu kami membahas celah kernel PwnEscape, yang menyerang lapisan kernel. PHP2Shell menyerang 1 lapisan di atasnya: runtime yang menjalankan hampir semua situs bisnis kecil di Indonesia.

Cara kerja: memori request yang tidak terjaga

Update ke PHP 8.5.12, 8.4.27, 8.3.36, atau 8.2.35 menutup kedua celah. Mitigasi lain hanya mengurangi paparan.

Bagian ini memakai ringkasan dari advisory resmi. Tujuannya membantu Anda memilih mitigasi yang tepat, bukan menjelaskan cara menyerang.

CVE-2026-109618: RCE via OOM corruption

Menurut GHSA-w8hw-w9fx-j79w, PHP memakai longjmp() untuk keluar dari konteks saat memori habis (out of memory, OOM). Pada beberapa konteks, data request baru terisi sebagian saat itu terjadi. Proses pembersihan request lalu membaca data yang belum siap itu sebagai data sah.

Advisory menulis bahwa pemicu OOM bisa datang dari body request multipart/form-data, yang PHP urai sebelum kode aplikasi jalan. Karena itu, banyak mitigasi sementara menyasar batas memori dan request multipart.

CVE-2026-109619: RCE via stale global state

Menurut GHSA-6wmf-4rv5-p3rp, PHP menyimpan state global, seperti state error, session, dan objek, yang sementara menunjuk ke memori request. Bila sebuah request terhenti oleh fatal error atau OOM, state itu bisa tidak di-reset. Request berikutnya di worker yang sama lalu membaca state basi itu (use-after-free).

Advisory menyebut 2 kasus yang sudah terkonfirmasi: fitur session.upload_progress, yang aktif secara bawaan, dan fatal_error_backtraces di PHP 8.5, yang juga aktif secara bawaan. Kedua nama pengaturan itu muncul lagi di langkah 4.

Dua kartu merah: CVE-2026-109618 OOM corruption dan CVE-2026-109619 stale global state, lalu kotak teal yang menyebut update PHP sebagai satu-satunya perbaikan lengkap.
(1) CVE-2026-109618: data request yang setengah terisi saat memori habis. (2) CVE-2026-109619: state global yang menunjuk memori yang sudah bebas. Kotak teal: patch menutup kedua jalur, mitigasi lain hanya mengurangi paparan.

Apa yang diubah patch

Patch untuk CVE-2026-109618 menghapus longjmp() saat OOM. Gantinya, PHP berhenti dengan rapi di titik aman berikutnya, dan berhenti keras dengan _exit() bila memori mencapai batas kedua yang lebih tinggi. Patch untuk CVE-2026-109619 mereset state global sebelum request berikutnya.

advisory keamanan php.net menulis dengan tegas: tidak ada mitigasi lengkap selain update. Karena itu, urutan kerja di artikel ini selalu dimulai dari update.

Siapa yang paling berisiko

Apache mod_php paling berisiko. PHP-FPM juga rentan, dan pada shared hosting, provider yang memasang patch.

Tingkat risiko bergantung pada cara PHP berjalan di server (SAPI). Tabel ini merangkum advisory keamanan php.net dan kedua advisory GHSA.

Cara PHP berjalanStatus di advisoryYang sudah terbuktiContoh tempat
Apache mod_phpRisiko tertinggiRCE lengkap lewat HTTP dengan batas bawaan, sebelum kode aplikasi jalanVPS lama, panel hosting dengan Apache prefork
PHP-FPMRentanRCE lewat jalur session upload progress (109619) tervalidasinginx + PHP-FPM, sebagian besar VPS modern
FrankenPHPKemungkinan rentanAnalisis kode sumber, belum divalidasiLaravel Octane, container modern
LiteSpeed (LSAPI)KandidatMirip FPM, exploit per aplikasi belum divalidasiShared hosting dengan LiteSpeed atau CyberPanel
php-cgiBerisikoMasuk daftar terdampak di php.netServer Windows dan setup lama
Lima kartu tingkat risiko per cara PHP berjalan: mod_php risiko tertinggi, PHP-FPM rentan, FrankenPHP mungkin rentan, LiteSpeed kandidat, php-cgi berisiko, plus catatan shared hosting.
Kartu merah: mod_php dan PHP-FPM, dengan jalur yang sudah divalidasi. Kartu amber: FrankenPHP, LiteSpeed, dan php-cgi. Kotak kanan bawah: pada shared hosting, provider memegang versi PHP.

Bila Anda memakai shared hosting, Anda tidak memegang versi PHP. Provider yang harus memasang patch. Anda tetap bisa mengecek versi lewat langkah 1, lalu meminta konfirmasi tertulis dari provider.

Versi yang sudah memuat patch

Tim PHP merilis 4 versi pada 21 Oktober 2026. Untuk cabang yang sudah habis masa dukungannya, tim PHP hanya memberi backport kode sumber minimal, tanpa biner resmi.

CabangVersi perbaikanStatusCatatan
8.58.5.12DidukungSampai update, set juga fatal_error_backtraces=0.
8.48.4.27DidukungUpdate sekarang.
8.38.3.36DidukungUbuntu 24.04: 8.3.6-0ubuntu0.24.04.13.
8.28.2.35Patch keamanan sampai 31 Desember 2026Rencanakan pindah ke 8.4 atau 8.5.
8.1, 8.0, 7.4Tanpa rilis resmiBackport kode sumber dari tim PHPUbuntu 22.04 php8.1: 8.1.2-1ubuntu2.28.
7.3 ke bawah, 5.xTanpa patchEnd of lifeUpgrade cabang, atau turunkan situs dari internet.
Tabel versi PHP aman per cabang: 8.5.12, 8.4.27, 8.3.36, 8.2.35, cabang 8.1 ke bawah tanpa rilis resmi, dan kotak versi paket Ubuntu dari USN-8948-1.
Kiri: versi upstream yang memuat patch. Kanan atas: paket Ubuntu memakai nomor sendiri, jadi cek changelog. Kanan bawah: repo Remi belum punya update pada 21 Oktober 2026.

Paket distro Linux memakai nomor versi sendiri. Ubuntu USN-8948-1 terbit pada 21 Oktober 2026 pukul 20.56 WIB untuk php8.1 (22.04), php8.3 (24.04), dan php8.5 (26.04). Nomor itu tidak sama dengan nomor upstream, jadi langkah 2 menunjukkan cara membuktikannya.

Pada pukul 22.00 WIB, halaman tracker Debian untuk CVE ini belum tersedia. advisory keamanan php.net juga menulis bahwa repo rpms.remirepo.net tidak punya update pada hari rilis, dan menyarankan paket distro atau build dari kode sumber.

Prasyarat sebelum mulai

  • Akses SSH ke setiap server yang menjalankan PHP, dengan hak sudo.
  • Daftar semua tempat PHP berjalan: VPS, container, panel hosting, server staging, dan aplikasi bawaan vendor.
  • Akses ke konfigurasi web server (nginx atau Apache) dan pool PHP-FPM.
  • Backup atau snapshot server yang baru, sebelum Anda mengubah paket.
  • Kontak support provider hosting, bila Anda memakai shared hosting atau managed hosting.

Langkah 1: Cek versi PHP yang dipakai web

Buka terminal di server, lalu jalankan perintah di bawah. Perintah kedua membandingkan versi PHP dengan versi perbaikan untuk cabangnya, lalu mencetak hasilnya dalam 1 baris.

php -v | head -1
php -r '$fix = ["8.2"=>"8.2.35", "8.3"=>"8.3.36", "8.4"=>"8.4.27", "8.5"=>"8.5.12"];
  $b = PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION; $v = PHP_VERSION;
  if (!isset($fix[$b])) { echo "$v: cabang tanpa rilis resmi. Upgrade.\n"; }
  elseif (version_compare($v, $fix[$b], "<")) { echo "$v: RENTAN. Update ke $fix[$b].\n"; }
  else { echo "$v: sudah memuat patch upstream.\n"; }'
Terminal container php:8.3.35: php -v menampilkan 8.3.35, lalu perintah php -r membandingkan versi dan mencetak 8.3.35 RENTAN, update ke 8.3.36.
Baris terakhir adalah hasil yang Anda cari. Uji ini memakai image resmi php:8.3.35 pada 21 Oktober 2026, karena tag 8.3.36 belum ada di Docker Hub saat itu.

CLI dan web bisa memakai PHP yang berbeda. Untuk memastikan versi yang melayani situs, buat berkas sementara di web root, buka lewat browser, lalu hapus berkas itu segera.

<?php // cek.php: buka lewat browser, lalu hapus berkas ini
echo PHP_VERSION, ' ', PHP_SAPI, "\n";

Cek hasil: Baris terakhir menulis "sudah memuat patch upstream", atau Anda lanjut ke langkah 2 bila PHP berasal dari paket distro. Hasil "RENTAN" pada paket distro belum tentu benar, karena distro memasang backport tanpa mengubah nomor versi.

Langkah 2: Cek patch di paket distro

Pada Ubuntu dan Debian, cek nomor paket dan changelog-nya. Changelog paket yang sudah ditambal memuat nomor kedua CVE.

dpkg-query -W -f='${Package} ${Version}\n' 'php*-common'
zgrep -o 'CVE-2026-10961[89]' /usr/share/doc/php8.3-common/changelog.Debian.gz | sort -u
Terminal Ubuntu 24.04: php -v menampilkan 8.3.6, dpkg-query menampilkan paket 8.3.6-0ubuntu0.24.04.13, dan zgrep menemukan CVE-2026-109618 serta CVE-2026-109619 di changelog paket.
php -v tetap menulis 8.3.6, padahal paket sudah memuat patch. Bukti yang benar adalah nomor paket dan 2 baris CVE di changelog.

Pada Rocky Linux, AlmaLinux, atau RHEL, pakai perintah ini.

rpm -q php-common
rpm -q --changelog php-common | grep -m2 -o 'CVE-2026-10961[89]'

Cek hasil: Changelog memuat CVE-2026-109618 dan CVE-2026-109619, dan nomor paket sama atau lebih baru dari Ubuntu USN-8948-1. Bila changelog kosong, paket Anda belum memuat patch.

Pengguna repo pihak ketiga, seperti PPA ondrej/php, harus mengecek changelog paket itu juga. Jangan anggap aman sebelum kedua CVE tercatat.

Langkah 3: Update PHP dan restart semua worker

Update paket PHP, lalu restart setiap service PHP. Worker lama tetap memakai kode lama sampai di-restart.

sudo apt update
sudo apt install --only-upgrade 'php8.3*'
sudo systemctl restart php8.3-fpm
sudo systemctl restart apache2   # bila memakai mod_php

Pada keluarga RHEL, pakai perintah ini.

sudo dnf upgrade 'php*'
sudo systemctl restart php-fpm httpd
Tangga 6 langkah: update PHP sebagai satu-satunya perbaikan lengkap, lalu 5 mitigasi sementara yang masing-masing berlabel belum aman.
(1) Kotak teal: update dan restart semua worker. (2) sampai (6): mitigasi sementara dari php.net. Label merah mengingatkan bahwa langkah 2 sampai 6 tidak membuat server aman.

Untuk container, rebuild image dari base image yang sudah memuat versi perbaikan. Pada uji kami pukul 22.00 WIB, tag terbaru php:8.3 di Docker Hub masih 8.3.35, jadi tunggu tag baru atau build dari kode sumber. Untuk Windows, unduh biner baru dari php.net.

Untuk cPanel, Plesk, atau CyberPanel, update lewat panel atau minta provider. advisory Plesk memuat status build PHP Plesk.

Cek hasil: Ulangi langkah 1 dan 2. Hasilnya harus "sudah memuat patch upstream", atau changelog memuat kedua CVE. Pastikan juga systemctl status menampilkan waktu start sesudah update.

Langkah 4 (opsional): Pasang mitigasi sementara bila belum bisa update

Langkah ini hanya untuk jeda pendek sampai update selesai. advisory keamanan php.net menulis bahwa langkah ini mengurangi paparan pada jalur tertentu, tetapi tidak membuat instalasi aman.

Tulis pengaturan di pool PHP-FPM, contoh /etc/php/8.3/fpm/pool.d/zz-php2shell.conf. Pakai php_admin_*, supaya aplikasi tidak dapat mengubahnya. Jangan andalkan ini_set() atau .user.ini.

[www]
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[memory_limit] = -1
php_admin_value[post_max_size] = 8M
; PHP 8.5 saja:
php_admin_flag[fatal_error_backtraces] = off
Terminal php:8.3.35-fpm: request lewat FPM menampilkan upload_progress=1 dan memory_limit=128M, lalu sesudah berkas pool baru dan reload menampilkan upload_progress=0 dan memory_limit=-1.
Baris pertama dan terakhir dibaca dari request yang dilayani worker FPM, bukan dari CLI. Nilai berubah hanya sesudah reload.

Nilai memory_limit=-1 membuat 1 request dapat memakai semua memori server. advisory keamanan php.net menyarankan batas container atau cgroup sebagai pengganti, dan melarang RLIMIT_AS atau RLIMIT_DATA. Untuk mod_php, tulis nilai yang sama di php.ini, lalu restart Apache.

Bila aplikasi tidak memakai upload, blokir request multipart di web server. Contoh nginx dari riset Sansec:

if ($http_content_type ~* "multipart/form-data") {
    return 403;
}

Contoh Apache, di setiap VirtualHost yang menjalankan PHP:

RewriteEngine On
RewriteCond %{HTTP:Content-Type} multipart/form-data [NC]
RewriteRule ^ - [F]

Blokir ini dapat merusak upload dan sebagian form checkout. Uji 1 pesanan sesudah memasangnya. catatan mitigasi Mattias Geniar menambahkan bahwa pada mod_php, blokir ini saja belum menutup celah.

curl -s -o /dev/null -w '%{http_code}\n' -F a=b https://domain-anda.com/

Cek hasil: Request lewat worker FPM menampilkan upload_progress=0, dan perintah curl di atas menjawab 403. Baca nilai dari request web, bukan dari php -i di CLI.

Langkah 5: Periksa tanda server sudah disentuh

Serangan ini berjalan di bawah lapisan aplikasi, jadi log aplikasi bisa sepi. riset Sansec dan tulisan Huntress menyebut tanda di log web server, proses, dan berkas.

grep -h -E 'Allowed memory size|PHP Fatal error' /var/log/php*-fpm.log /var/log/apache2/error.log | tail -50
awk '$9 == 500' /var/log/nginx/access.log | wc -l
ps -eo pid,ppid,user,etime,cmd --forest | grep -A3 -E 'php-fpm|apache2|httpd'
find /var/www -name '*.php' -newermt '2026-10-20' -ls
crontab -l -u www-data
Dua kolom tanda serangan: di log web server dan di proses serta berkas, lalu kotak merah berisi tindakan bila ada tanda.
Kolom amber: tanda di log, seperti error memory_limit dan HTTP 500 berulang. Kolom merah: proses shell dari worker PHP dan berkas baru di web root. Kotak bawah: isolasi, simpan log, ganti kredensial.

Cari 4 pola. Pertama, request multipart tidak biasa yang diikuti error memory_limit atau HTTP 500 berulang. Kedua, worker PHP yang menjalankan sh, bash, curl, atau wget.

Ketiga, berkas PHP baru di web root sejak 20 Oktober 2026. Keempat, cron atau akun baru milik user web.

Cek hasil: Tidak ada proses shell dari worker PHP, dan tidak ada berkas PHP baru yang tidak Anda kenal. Bila ada tanda, isolasi server, simpan log web dan PHP, lalu ganti semua kredensial yang tersimpan di server itu.

Contoh: 1 malam respons untuk 3 server

Simulasi ini memakai data dummy. Nama server, waktu, dan hasil bukan data pelanggan.

Waktu (WIB)Server dummyYang dicekHasilTindakan
21.15web-toko (Ubuntu 24.04, FPM)Langkah 2: changelogKedua CVE belum adaapt upgrade, restart php8.3-fpm
21.30web-tokoUlangi langkah 28.3.6-0ubuntu0.24.04.13, kedua CVE adaSelesai, catat bukti
21.40web-blog (shared hosting)Langkah 1: cek.php8.2.30, RENTANTiket ke provider, minta jam patch tertulis
21.50web-lama (CentOS 7, PHP 7.4)Langkah 1Cabang tanpa rilis resmiMitigasi langkah 4, mode read-only, jadwal migrasi
22.10SemuaLangkah 5Tidak ada proses shell dari workerSimpan output sebagai bukti

Pelajaran dari simulasi: server dengan paket distro selesai paling cepat. Server dengan cabang PHP lama butuh keputusan bisnis, bukan hanya perintah terminal.

Siapa yang memasang patch

Tanggung jawab patch berbeda per jenis hosting. Tabel ini membantu Anda tahu siapa yang harus bergerak malam ini.

Jenis hostingPemegang versi PHPYang Anda kerjakan
VPS atau server sendiriAndaLangkah 1 sampai 5
Shared hosting (cPanel, CyberPanel, Plesk)ProviderLangkah 1, lalu minta konfirmasi patch tertulis
Managed WordPress atau managed hostingProviderMinta konfirmasi tertulis, lalu langkah 5 lewat log yang tersedia
Container (Docker, Kubernetes)Tim yang membuat imageRebuild image, deploy ulang, lalu langkah 1 di container
Aplikasi vendor dengan PHP bawaanVendorTanya vendor, dan batasi akses dari internet sampai patch ada

Rekomendasi Rama Digital: bila situs Anda memproses pembayaran atau data pelanggan dan provider belum menjawab dalam beberapa jam, pasang mode read-only atau turunkan situs sementara. checklist keamanan server toko online memuat daftar kontrol lain untuk server toko online.

Checklist malam ini

  1. Inventaris semua server PHP. Pemilik: admin server. Bukti: daftar host dengan cabang PHP.
  2. Cek versi web dengan langkah 1. Pemilik: admin server. Bukti: output perintah per host.
  3. Cek changelog paket dengan langkah 2. Pemilik: admin server. Bukti: 2 baris CVE per host.
  4. Update dan restart semua worker. Pemilik: admin server. Bukti: waktu start service sesudah update.
  5. Minta konfirmasi tertulis dari provider hosting. Pemilik: pemilik bisnis. Bukti: email atau tiket support.
  6. Pasang mitigasi langkah 4 di server yang belum bisa update. Pemilik: admin server. Bukti: output request FPM dan kode 403.
  7. Periksa tanda serangan dengan langkah 5. Pemilik: admin server. Bukti: output perintah, disimpan bersama log.
  8. Berhenti bila semua server lolos langkah 2 dan langkah 5 tidak menemukan tanda. Bila ada tanda, hentikan kerja patch dan mulai respons insiden.

Pertanyaan yang sering muncul

Apakah WordPress saya terdampak walau plugin sudah update? Ya, bila versi PHP di server belum memuat patch. Celah ada di mesin PHP, jadi update WordPress dan plugin tidak menutupnya. Cek versi PHP dengan langkah 1.

Apakah php -v yang menulis 8.3.6 berarti server saya rentan? Belum tentu. Ubuntu 24.04 memakai nomor 8.3.6 dengan backport patch. Cek nomor paket dan changelog dengan langkah 2 untuk bukti yang benar.

Apakah WAF atau Cloudflare sudah melindungi server saya? Tidak. riset Sansec menyebut WAF sebagai penahan sementara untuk sebagian bentuk request, bukan perbaikan. WAF juga hanya membantu bila origin menolak trafik yang tidak lewat CDN.

Server saya masih PHP 7.4. Apa pilihan saya? Tim PHP hanya memberi backport kode sumber untuk 7.4, 8.0, dan 8.1, tanpa biner resmi. Pilihannya: paket backport dari vendor LTS, upgrade cabang PHP, atau lepaskan server dari internet.

Apakah mematikan session.upload_progress sudah menutup celah? Tidak. riset Sansec mengutip peringatan bahwa pengaturan ini saja belum menutup celah. Pengaturan itu menutup 1 jalur yang terkonfirmasi, bukan semua varian.

Bagaimana saya tahu server sudah dibobol? Cari proses shell dari worker PHP, berkas PHP baru di web root, dan cron baru milik user web, seperti di langkah 5. Log yang bersih tidak membuktikan server aman.

Langkah berikutnya

Batas yang tetap berlaku: update menutup 2 celah ini, tetapi tidak menghapus akses yang mungkin sudah tertanam sebelum patch. Bila server Anda menunjukkan tanda di langkah 5, atau Anda butuh bantuan memeriksa aplikasi PHP sesudah insiden, pakai Vibe Code Rescue untuk audit dan stabilisasi. Untuk 1 kendala yang mendesak malam ini, Jadwalkan sesi 30 menit. Baca juga standar audit keamanan aplikasi untuk audit lanjutan.

Sumber