Kurz gesagt: Bei Nginx mit PHP-FPM steckt die Lücke aus PHP2Shell in PHP-FPM, nicht in Nginx. Patchen Sie alle PHP-FPM-Versionen, starten Sie jeden FPM-Dienst vollständig neu und belegen Sie das mit Prozess-Startzeiten. Für die Nginx PHP-FPM Sicherheit auf Dauer zählen getrennte Pools, nicht überschreibbare Werte und eine Nginx-Konfiguration, die keine hochgeladenen Dateien ausführt.
Wie Nginx und PHP-FPM zusammenarbeiten
Nginx liefert statische Dateien selbst aus und reicht Anfragen an PHP-Skripte über FastCGI an PHP-FPM weiter. PHP-FPM besteht aus einem Master-Prozess und mehreren Worker-Prozessen, gruppiert in Pools. Ein Worker bearbeitet nacheinander viele Anfragen.
Genau das ist für PHP2Shell relevant. Bei CVE-2026-109619 kann interner Zustand einer Anfrage nach dem Freigeben des Speichers bestehen bleiben und von einer späteren Anfrage im selben Worker genutzt werden. Bei CVE-2026-109618 kann ein Out-of-Memory-Zustand PHP mitten in der Initialisierung einer Anfrage unterbrechen. Beide Lücken sind mit CVSS v4.0 9.2 bewertet und behoben in PHP 8.5.12, 8.4.27, 8.3.36 und 8.2.35.
Bestand prüfen: Versionen, Pools, Prozesse
Viele Server haben mehrere PHP-FPM-Versionen parallel. Die folgenden Befehle lesen nur; Paket- und Dienstnamen sind Beispiele für Debian/Ubuntu und die RHEL-Familie.
# Welche FPM-Dienste laufen?
systemctl list-units --type=service | grep -i fpm
# Welche Version steckt dahinter? (Beispiel Debian/Ubuntu)
php-fpm8.3 -v
# RHEL-Familie
php-fpm -v
# An welche Sockets oder Ports reicht Nginx weiter?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'
# Pools und ihre Benutzer
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
Gleichen Sie jeden fastcgi_pass-Eintrag mit einem laufenden Pool ab. So sehen Sie, welche PHP-Version welche Website bedient. Bei Distributionspaketen belegt das Änderungsprotokoll mit den CVE-Nummern den Patch, nicht allein die Versionsnummer.
Ein häufiger Befund bei solchen Bestandsaufnahmen sind Server, auf denen über die Jahre mehrere PHP-Versionen installiert wurden, von denen nur eine tatsächlich in Gebrauch ist. Die übrigen FPM-Dienste laufen trotzdem weiter, oft mit Standard-Pools, die auf einem lokalen Socket oder Port lauschen. Sie sind von außen meist nicht direkt erreichbar, bleiben aber ein unnötiges Risiko und verlängern jede Notfallaktualisierung. Deaktivieren und entfernen Sie Versionen, die keine Website nutzt, nachdem Sie die Zuordnung über die fastcgi_pass-Einträge geprüft haben.
Ebenso lohnt ein Blick auf den Benutzer der Pools. Laufen alle Pools als www-data oder nginx, ist die Trennung zwischen den Websites nur auf dem Papier vorhanden. Wer eine Website übernimmt, kann dann die Dateien aller anderen lesen, etwa Konfigurationsdateien mit Datenbankpasswörtern. Eigene Systembenutzer je Pool und passende Dateirechte schaffen hier eine echte Grenze. Das ist keine Abhilfe für PHP2Shell, begrenzt aber den möglichen Schaden eines erfolgreichen Angriffs deutlich.
Patch einspielen und alle Worker erneuern
Nach dem Paketupdate starten Sie jeden PHP-FPM-Dienst neu. Ein Reload ersetzt zwar die Worker, ein vollständiger Neustart erneuert aber auch den Master-Prozess und ist nach Sicherheitsupdates der sichere Weg.
# Beispiel Debian/Ubuntu, je installierter Version
systemctl restart php8.3-fpm
# RHEL-Familie
systemctl restart php-fpm
# Kontrolle: Startzeit von Master und Workern
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
Jeder Prozess muss nach dem Update gestartet sein. Ausführlich beschrieben ist das unter PHP-FPM und alle Worker neu starten.
Ein Patch entfernt keine Schadsoftware, die vorher eingeschleust wurde. Bewahren Sie die Nginx-Zugriffs- und Fehlerprotokolle ab dem 20.10.2026 auf und prüfen Sie die Websites auf Spuren.
Übergangswerte im Pool setzen
Solange eine Version nicht gepatcht ist, empfiehlt php.net Übergangsmaßnahmen. Sie bieten keinen vollständigen Schutz. In PHP-FPM setzen Sie die Werte mit php_admin_value beziehungsweise php_admin_flag im Pool, dann können Anwendungen sie per ini_set() nicht überschreiben.
; Beispiel: /etc/php/8.3/fpm/pool.d/website.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
Ohne Upload-Funktion nennt php.net post_max_size = 8M. Auf PHP 8.5 kommt fatal_error_backtraces=0 hinzu. Für den Hinweis zu memory_limit=-1 brauchen Sie eine Speichergrenze auf cgroup-Ebene, etwa über MemoryMax in einer systemd-Ergänzung für den FPM-Dienst. Passen Sie in Nginx client_max_body_size an die neue post_max_size an, damit Nutzer verständliche Fehlermeldungen erhalten. Danach FPM neu starten.
Nginx PHP-FPM Sicherheit dauerhaft verbessern
Über den akuten Fall hinaus helfen einige Grundregeln, die den Schaden bei künftigen Lücken begrenzen:
- Ein Pool je Website mit eigenem Systembenutzer, eigenem Socket und eigener
open_basedir-Grenze. Mehr unter open_basedir und Isolation pro Website. - Socket-Rechte so setzen, dass nur Nginx zugreifen kann, keine FPM-Ports nach außen öffnen.
- Nur existierende Skripte ausführen: In der PHP-Location
try_files $uri =404;setzen, damit Nginx keine Pfade an PHP weitergibt, die es nicht gibt. - Uploads nicht ausführen: In Upload-Verzeichnissen PHP-Ausführung verbieten. Hinweise dazu stehen unter Datei-Uploads sicher umsetzen.
- Status-Seiten schützen:
pm.status_pathundping.pathnur intern erreichbar machen.
# Beispiel: keine PHP-Ausführung im Upload-Verzeichnis
location ~* ^/uploads/.*\.php$ {
deny all;
}
Prüfen Sie jede Änderung mit nginx -t, bevor Sie Nginx neu laden. Halten Sie außerdem fest, welche Pools, Versionen und Sonderregeln auf dem Server bestehen. Diese kurze Dokumentation spart bei der nächsten kritischen Lücke wertvolle Zeit, weil niemand erst suchen muss, welche Website an welchem Pool hängt.
Wie hilft PHP SOS konkret?
- Wir ordnen jede Website ihrem Pool und ihrer PHP-Version zu und prüfen den tatsächlichen Paketstand.
- Wir patchen, starten alle FPM-Dienste neu und dokumentieren Prozess-Startzeiten als Nachweis.
- Bis zum Patch setzen wir die Übergangswerte je Pool und begrenzen den Speicher per cgroup.
- Im Rahmen der Server-Härtung trennen wir Pools, Rechte und Upload-Verzeichnisse sauber.
- Bei Verdacht auf einen Einbruch übernehmen wir die Incident Response.
Häufige Fragen
Reicht systemctl reload für PHP-FPM nach einem Update?
Ein Reload erneuert die Worker, der Master-Prozess kann aber den alten Code behalten. Nach einem Sicherheitsupdate ist ein vollständiger Neustart des Dienstes der sichere Weg. Kontrollieren Sie danach die Startzeit von Master und Workern.
Muss Nginx nach einem PHP-Update neu gestartet werden?
Nginx selbst enthält kein PHP und muss für den PHP-Patch nicht neu starten. Neu starten müssen alle PHP-FPM-Dienste. Ändern Sie dabei die Nginx-Konfiguration, prüfen Sie sie vor dem Neuladen mit nginx -t.
Warum eigene Pools je Website?
Jeder Pool läuft mit eigenem Benutzer und eigenen Grenzen. Wird eine Website kompromittiert, kommt der Angreifer nicht ohne Weiteres an die Dateien der anderen. Zudem lassen sich Übergangswerte gezielt je Pool setzen.
Ist pm.max_requests ein Schutz gegen PHP2Shell?
Nein, es ersetzt keinen Patch. Der Wert begrenzt, wie viele Anfragen ein Worker bearbeitet, bevor er ersetzt wird. Das kann die Lebensdauer von Zuständen im Prozess verkürzen, ist aber keine von php.net genannte Abhilfe.