Krótko: FrankenPHP to serwer aplikacji oparty na Caddy, który osadza PHP we własnym programie. Dla bezpieczeństwa FrankenPHP po PHP2Shell oznacza to: nie liczą się pakiety PHP dystrybucji, tylko wersja PHP w binarce FrankenPHP lub w obrazie kontenera. Proszę zbudować lub pobrać wersję z usuniętą luką w PHP i zrestartować wszystkie workery.
Dlaczego FrankenPHP łata się inaczej
W klasycznych konfiguracjach dystrybucja dostarcza PHP jako pakiet, a aktualizacja podmienia pliki. FrankenPHP natomiast zawiera PHP jako wbudowaną bibliotekę. Kto używa oficjalnej binarki lub opartego na niej obrazu kontenera, dostaje PHP w zestawie. apt upgrade na hoście niczego tu nie zmienia.
PHP2Shell obejmuje CVE-2026-109618 i CVE-2026-109619, każda z oceną CVSS v4.0 9.2. Projekt PHP wprost wymienia FrankenPHP wśród dotkniętych trybów pracy. Usunięte są PHP 8.5.12, 8.4.27, 8.3.36 i 8.2.35. Rozstrzyga więc, z jaką wersją PHP zbudowano Państwa FrankenPHP.
Tryb worker a PHP2Shell
FrankenPHP może uruchamiać aplikacje w trybie worker. Aplikacja jest ładowana raz i potem obsługuje wiele żądań jedno po drugim w tym samym procesie. Daje to szybkość, ale wydłuża czas życia każdego procesu.
CVE-2026-109619 opisuje wewnętrzny stan żądania, który może pozostać po zwolnieniu pamięci; późniejsze żądanie w tym samym workerze może go użyć, zanim zostanie zresetowany. W trybie worker współdziałanie wielu żądań w jednym procesie jest normą. To nie powód, aby rezygnować z trybu worker, ale wyraźny powód, aby aktualizacje i restarty wykonywać szczególnie starannie. Szczegóły techniczne podaje artykuł CVE-2026-109619.
Bezpieczeństwo FrankenPHP: sprawdzenie wersji
Proszę sprawdzić wbudowaną wersję PHP bezpośrednio w działającym systemie. Poniższe polecenia tylko odczytują; nazwy usług i kontenerów to przykłady.
# Zainstalowana binarka
frankenphp version
# W działającym kontenerze (nazwa kontenera jako przykład)
docker exec app frankenphp version
docker exec app php -v
# Jaki obraz faktycznie działa? (digest pokazuje dokładny stan)
docker inspect --format '{{.Image}} {{.Config.Image}}' app
Proszę zanotować wersję PHP z wyniku. Jeśli jest wcześniejsza niż wersje z usuniętą luką, system jest podatny. Zawsze proszę sprawdzać działający kontener, a nie tylko ostatnio zbudowany obraz, bo nowy obraz zaczyna działać dopiero po wymianie kontenerów.
Instalacja aktualizacji i restart wszystkich workerów
Wygląd aktualizacji zależy od Państwa instalacji:
- Binarka na hoście: zainstalować nowe wydanie FrankenPHP z usuniętą luką w wersji PHP, zrestartować usługę.
- Kontener: pobrać obraz bazowy z usuniętą luką w wersji PHP, przebudować własny obraz bez cache dla warstwy bazowej, wymienić kontener.
- Kompilowane samodzielnie: zbudować od nowa z wersją PHP z usuniętą luką, wszystkie rozszerzenia wygenerować ponownie w tej samej wersji.
# Przykład instalacji na hoście jako usługa systemd
systemctl restart frankenphp
# Przykład Docker Compose: przebudowa bez cache i wymiana kontenera
docker compose build --pull --no-cache
docker compose up -d --force-recreate
Potem proszę ponownie sprawdzić wersję PHP w działającym kontenerze i czas startu procesów. W trybie worker każdy worker musi być zrestartowany. W Kubernetes obowiązują dodatkowe kroki, opisane w artykule Łatanie PHP w Kubernetes, a dla kontenerów ogólnie w artykule Łatanie PHP w kontenerach Docker.
Tag taki jak latest lub wersja główna w nazwie obrazu nie gwarantuje, że mają Państwo najnowszy stan. Proszę aktywnie pobrać obraz bazowy na nowo i potem sprawdzić wersję PHP w działającym kontenerze.
Środki przejściowe i utwardzanie
Jeśli aktualizacja nie może nastąpić od razu, php.net zaleca środki przejściowe, które nie dają pełnej ochrony. W FrankenPHP wartości ustawia się w pliku php.ini, który ładuje FrankenPHP, lub przez ustawienia PHP w konfiguracji Caddy, a nie przez ini_set() w aplikacji.
; php.ini w kontenerze lub na hoście
session.upload_progress.enabled = 0
post_max_size = 8M
upload_max_filesize = 6M
Przy funkcji uploadu php.net podaje post_max_size = 32M. W PHP 8.5 dochodzi fatal_error_backtraces=0. Limit pamięci należy do poziomu kontenera, na przykład przez limit pamięci kontenera, a nie przez RLIMIT_AS czy RLIMIT_DATA. Po każdej zmianie proszę zrestartować wszystkie workery.
Przy długotrwałej pracy opłaca się odwoływać do obrazów ze stałym digestem, regularnie je automatycznie przebudowywać i włączyć skaner obrazów do łańcucha budowania. Poprawka nie usuwa przy tym szkodliwego oprogramowania wprowadzonego wcześniej. Proszę zachować logi od 20.10.2026; w przypadku kontenerów oznacza to zabezpieczenie ich przed wymianą.
Kto używa FrankenPHP jako statycznie zbudowanej binarki, powinien wiedzieć, że oprócz PHP na stałe wbudowane są tam także wszystkie rozszerzenia. Aktualizacja oznacza więc zawsze wymianę całej binarki. Po wymianie proszę sprawdzić wersję i listę załadowanych rozszerzeń, czy wszystko jest dostępne jak poprzednio, i przetestować aplikację, zanim odrzucą Państwo stary stan. W środowiskach kontenerowych zaleca się oznaczać każdy obraz datą budowy. Dzięki temu można w każdej chwili odtworzyć, jaki stan działał kiedy, i w razie wątpliwości celowo się cofnąć, nie wracając ponownie do stanu podatnego. Przypisanie obrazu, wersji PHP i momentu proszę zapisać w dokumentacji.
Jak konkretnie pomaga PHP SOS?
- Sprawdzamy, jaka wersja PHP faktycznie tkwi w Państwa binarkach FrankenPHP i działających kontenerach.
- Przez usługę aktualizacji PHP przebudowujemy obrazy, wymieniamy kontenery i restartujemy wszystkie workery, z dowodem.
- Zabezpieczamy logi przed wymianą i sprawdzamy aplikację pod kątem śladów.
- Na potrzeby długotrwałej pracy wdrażamy zautomatyzowane przebudowy i kontrole obrazów w ramach utwardzania serwerów.
Częste pytania
Czy aktualizacja apt lub dnf pomaga przy FrankenPHP?
Tylko jeśli sam FrankenPHP pochodzi z tych źródeł pakietów i został zbudowany z załatanym PHP. Często PHP jest na stałe zawarte w binarce FrankenPHP lub w obrazie kontenera. Wtedy trzeba zaktualizować binarkę lub obraz.
Dlaczego tryb worker jest przy PHP2Shell szczególnie ważny?
W trybie worker aplikacja pozostaje w pamięci i obsługuje wiele żądań po kolei w tym samym procesie. CVE-2026-109619 dotyczy właśnie stanu wewnętrznego, który może pozostać między żądaniami w tym samym workerze. Restart wszystkich workerów po aktualizacji jest więc obowiązkowy.
Jak sprawdzić, jaka wersja PHP jest w FrankenPHP?
Binarka FrankenPHP przy wywołaniu wersji podaje wbudowaną wersję PHP. W kontenerze można wykonać to polecenie przez docker exec. Proszę zadbać o sprawdzenie wersji w faktycznie działającym kontenerze, a nie w nowo zbudowanym obrazie.
Czy dla FrankenPHP są osobne środki przejściowe?
Obowiązują ogólne wskazówki php.net. Wartości ustawia się w pliku php.ini, który ładuje FrankenPHP, lub w konfiguracji PHP w pliku Caddy, a nie przez ini_set() w aplikacji. Potem trzeba zrestartować wszystkie workery.