Stand: 21. Oktober 2026, Vormittag. Die gepatchten PHP-Versionen sind für heute 16:00 Uhr (MESZ) angekündigt. Ich aktualisiere diesen Beitrag, sobald das offizielle Advisory da ist.
Diese PHP-Sicherheitslücke betrifft nicht ein einzelnes Plugin, sondern PHP selbst. Also die Grundlage, auf der WordPress, WooCommerce, Laravel, Shopware und fast jede andere dynamische Website laufen. Das PHP-Team stuft beide Lücken als kritisch ein, mit 9,2 von 10 Punkten [php.net]. Und das Unangenehme: Die Details sind durchgesickert, bevor es einen Patch gibt.
Weiter unten findest du fertige Skripte für Ubuntu/Debian-Server, CloudPanel, Laravel Forge und Cloudflare. Für CloudPanel gibt es außerdem ein komplettes Skript zum Ein- und Ausschalten auf vielen Servern als GitHub Gist. Vielleicht spart das dem einen oder anderen heute ein paar Stunden.
Was ist passiert?
Am 20. Oktober hat das PHP-Sicherheitsteam ein Notfall-Release angekündigt: zwei kritische Schwachstellen, CVE-2026-109618 und CVE-2026-109619. Der Termin für die gepatchten Versionen ist Mittwoch, 21. Oktober 2026, 14:00 UTC – das ist 16:00 Uhr bei uns. Betroffene und gefixte Versionen nennt PHP erst mit dem Release. Das Team behält sich vor, früher zu veröffentlichen, falls Angriffe auftauchen [php.net].
Schon vorher sind laut Sicherheitsforschern Details öffentlich geworden. Mehrere Firmen sprechen von Remote Code Execution: Ein Angreifer könnte ohne Login eigenen Code auf dem Server ausführen. Die Lücke steckt nach bisherigen Berichten in der Verarbeitung von Datei-Uploads (multipart/form-data), insbesondere im Upload-Fortschritt der Sessions. PHP hat das nicht bestätigt [Vincent Schmalbach, Sansec].
Bestätigte Angriffe gab es bis heute früh keine. Sansec rechnet aber mit Massenangriffen sehr kurz nach dem Release, weil Angreifer dann den Patch vergleichen und den Fehler gezielt nachbauen können [Vincent Schmalbach].
Bist du von der PHP-Sicherheitslücke betroffen?
Sehr wahrscheinlich ja, wenn deine Website mit PHP läuft. CERT-EU schreibt, dass potenziell alle Versionen ab PHP 5 betroffen sein könnten, und rät, internetseitige Anwendungen notfalls vom Netz zu nehmen, bis ein Fix da ist [CERT-EU].
Wichtig für WordPress-Seiten: Es spielt keine Rolle, ob du ein Upload-Formular hast. PHP verarbeitet die Anfrage, bevor WordPress oder ein Sicherheits-Plugin überhaupt etwas davon mitbekommt. Wordfence, Maintenance-Modus oder Login-Schutz helfen hier nicht.
Offiziell unterstützt PHP derzeit die Zweige 8.2 bis 8.5. PHP 8.1 und älter bekommen sehr wahrscheinlich keinen Fix. Wenn deine Seite noch auf einer alten Version läuft, ist jetzt der Zeitpunkt für das Upgrade.
Was du jetzt tun solltest – je nach Hosting
Shared Hosting oder Managed Hosting
Hier patcht dein Hoster PHP, nicht du. Was du tun kannst:
- Schreib deinem Hoster heute noch und frag konkret: Wann wird der gepatchte PHP-Build eingespielt, und welche Version läuft dann für meine Domain?
- Prüf im Hosting-Panel, welche PHP-Version deine Seite nutzt. Steht dort 8.1 oder älter: auf 8.3 oder 8.4 umstellen und die Seite danach durchklicken.
- Als Übergangslösung kannst du den Upload-Fortschritt abschalten. Leg dafür im Hauptordner deiner Website (dort, wo die
index.phpliegt) eine Datei.user.inian oder ergänze eine bestehende um diese Zeile. Das wirkt nach bis zu fünf Minuten.
session.upload_progress.enabled = Off
Das ist nur ein Pflaster. Laut Berichten gibt es möglicherweise einen zweiten Angriffsweg, den diese Einstellung nicht abdeckt.
Eigener Server (VPS, Root-Server, Cloud)
Hier liegt die Verantwortung bei dir. Bis zum Patch helfen zwei Maßnahmen. Beide sind keine offizielle Empfehlung von PHP – ein PHP-Core-Entwickler hat klargestellt, dass nur das Update wirklich schützt. Sie senken das Risiko aber für die paar Stunden bis dahin [Vincent Schmalbach].
- Upload-Fortschritt abschalten – in der php.ini und bei PHP-FPM zusätzlich fest in jedem Pool, damit eine
.user.inidie Einstellung nicht wieder einschalten kann. - Multipart-Anfragen am Webserver blocken – die stärkere Maßnahme. Jede Anfrage mit „multipart“ im Content-Type wird abgewiesen, bevor sie PHP erreicht, für alle HTTP-Methoden, nicht nur POST.
Die fertigen Befehle dafür findest du weiter unten.
Die Nebenwirkung musst du kennen: Solange der Block aktiv ist, funktionieren keine Datei-Uploads. Das betrifft die WordPress-Mediathek, Formulare mit Anhang und Upload-Felder in Laravel-Apps. Contact Form 7 schickt auch Formulare ohne Dateifeld als multipart – die fallen also ebenfalls aus. Normale Seiten, Logins und Formulare ohne multipart laufen weiter. Für ein paar Stunden ist das in den meisten Fällen verkraftbar.
Hinter Cloudflare oder einer anderen Firewall
Eine WAF davor kann zusätzlich blocken. Sie schützt aber nur Anfragen, die auch durch sie durchgehen. Wer deine Server-IP kennt, geht direkt drumherum. Der Block gehört deshalb immer auch auf den Server selbst.
Fertige Skripte zum Kopieren
Die Skripte setzen beide Übergangsmaßnahmen um. Sie sind für Ubuntu/Debian mit nginx und PHP-FPM gedacht. Lies sie kurz durch, bevor du sie ausführst, und teste danach.
Zur Map-Variante: Die Regel unten blockt neben multipart auch jede Anfrage mit PHPSESSID im Cookie oder in der URL (auch URL-codiert). Das schließt den Session-Weg mit ab, sperrt aber auch eingeloggte Nutzer von Anwendungen aus, die PHP-Sessions verwenden (z. B. phpMyAdmin, manche Shops und ältere Plugins). WordPress und Laravel nutzen eigene Cookies und merken davon meist nichts. Willst du nur Uploads blocken, nimm die Zeile mit dem langen Muster raus.
Upload-Fortschritt aus – für alle PHP-Versionen
Als root ausführen. Setzt die Einstellung in jeder php.ini und jedem FPM-Pool und lädt alle PHP-FPM-Dienste neu:
for ini in /etc/php/*/fpm/php.ini; do
sed -i 's/^;?s*session.upload_progress.enabled.*/session.upload_progress.enabled = 0/' "$ini"
grep -q '^session.upload_progress.enabled' "$ini" || echo 'session.upload_progress.enabled = 0' >> "$ini"
done
for pool in /etc/php/*/fpm/pool.d/*.conf; do
grep -q 'session.upload_progress.enabled' "$pool" ||
echo 'php_admin_flag[session.upload_progress.enabled] = off' >> "$pool"
done
for s in $(systemctl list-units --type=service --no-legend 'php*-fpm*' | awk '{print $1}'); do
systemctl reload "$s"
done
grep -H 'session.upload_progress.enabled' /etc/php/*/fpm/php.ini
nginx: Map und Guard
Die Map gehört in den http { }-Kontext, am einfachsten als eigene Datei /etc/nginx/conf.d/php2shell.conf:
map "$http_cookie|$args|$content_type" $block_php2shell {
default 0;
"~*(?:p|%[57]0)(?:h|%[46]8)(?:p|%[57]0)(?:s|%[57]3)(?:e|%[46]5)(?:s|%[57]3)(?:s|%[57]3)(?:i|%[46]9)(?:d|%[46]4)" 1;
"~*multipart/form-data" 1;
}
Und oben in jeden server { }-Block, der an PHP weitergibt – inklusive Default- bzw. Catch-all-Server:
if ($block_php2shell) { return 403; }
Danach:
nginx -t && systemctl reload nginx
Apache 2.4
In den VirtualHost oder in die .htaccess oberhalb der WordPress-Regeln. Nimm genau req('Content-Type') – %{CONTENT_TYPE} meint bei Apache den Typ der Antwort, damit läuft der Block ins Leere:
<If "req('Content-Type') =~ /multipart/i">
Require all denied
</If>
CloudPanel
Am schnellsten mit dem fertigen Skript: Es schaltet den Upload-Fortschritt in allen PHP-Versionen aus, legt die Map an, setzt den Guard in alle Vhosts (inklusive Default-Host), sichert vorher /etc/nginx und rollt bei einem nginx-Fehler automatisch zurück. Mit off entfernst du alles wieder. Du findest es als php2shell-cloudpanel.sh auf GitHub Gist.
# ein Server
bash php2shell-cloudpanel.sh on
# viele Server auf einmal
for h in web01 web02 web03; do ssh root@$h 'bash -s' < php2shell-cloudpanel.sh on; done
# nur Uploads blocken, PHPSESSID nicht (z. B. Server mit CRM oder Shop)
ssh root@web01 'MULTIPART_ONLY=1 bash -s' < php2shell-cloudpanel.sh on
# nach dem PHP-Update
bash php2shell-cloudpanel.sh off
Wichtig: Das Skript schreibt direkt in die Vhost-Dateien. Solange der Block aktiv ist, keinen Vhost in der CloudPanel-Oberfläche speichern – sonst ist der Guard für diese Site weg.
Lieber von Hand? So geht es Schritt für Schritt:
- Per SSH als root das Skript „Upload-Fortschritt aus“ von oben ausführen. CloudPanel hat meist mehrere PHP-Versionen installiert, das Skript erwischt alle.
- Die Map als
/etc/nginx/conf.d/php2shell.confanlegen. Mitgrep -n "conf.d" /etc/nginx/nginx.confprüfen, ob der Ordner geladen wird. Falls nicht, die Map direkt in denhttp { }-Block der/etc/nginx/nginx.confschreiben. - In der CloudPanel-Oberfläche: Sites → Site → Vhost. Die Guard-Zeile oben in jeden
server { }-Block setzen. PHP-Sites haben oft zwei Blöcke (z. B. 80/443 und 8080 für Varnish). Speichern. Über die Oberfläche ändern, nicht direkt in/etc/nginx/sites-enabled/– sonst überschreibt CloudPanel das beim nächsten Speichern. - Den Default-Host suchen und ebenfalls absichern:
grep -rln "default_server" /etc/nginx/sites-enabled/ /etc/nginx/conf.d/ nginx -t && systemctl reload nginxund von außen testen (siehe unten).
Laravel Forge als Recipe
In Forge unter Recipes → New Recipe anlegen, User root, dann auf die gewünschten Server ausführen. Das Recipe legt den Guard automatisch für jede Site ab und rollt bei einem nginx-Fehler alles zurück. Neuere Forge-Server benennen die Ordner unter forge-conf/ nach der Site-ID statt nach der Domain – die Schleife erwischt beides. Der Forge-Catch-all antwortet ohnehin mit 444.
Recipe „PHP2Shell Stopgap AN“
#!/bin/bash
set -e
# 1. Upload-Progress aus, alle PHP-Versionen
for ini in /etc/php/*/fpm/php.ini; do
sed -i 's/^;?s*session.upload_progress.enabled.*/session.upload_progress.enabled = 0/' "$ini"
grep -q '^session.upload_progress.enabled' "$ini" || echo 'session.upload_progress.enabled = 0' >> "$ini"
done
# auch fest in jedem FPM-Pool (gegen .user.ini)
for pool in /etc/php/*/fpm/pool.d/*.conf; do
grep -q 'session.upload_progress.enabled' "$pool" ||
echo 'php_admin_flag[session.upload_progress.enabled] = off' >> "$pool"
done
for s in $(systemctl list-units --type=service --no-legend 'php*-fpm*' | awk '{print $1}'); do
systemctl reload "$s"
done
# 2. nginx Map (http-Kontext)
cat > /etc/nginx/conf.d/php2shell.conf <<'EOF'
map "$http_cookie|$args|$content_type" $block_php2shell {
default 0;
"~*(?:p|%[57]0)(?:h|%[46]8)(?:p|%[57]0)(?:s|%[57]3)(?:e|%[46]5)(?:s|%[57]3)(?:s|%[57]3)(?:i|%[46]9)(?:d|%[46]4)" 1;
"~*multipart/form-data" 1;
}
EOF
# 3. Guard in jede Forge-Site (server-Kontext)
for dir in /etc/nginx/forge-conf/*/server; do
echo 'if ($block_php2shell) { return 403; }' > "$dir/00-php2shell.conf"
done
# 4. Testen, bei Fehler alles zurückrollen
if nginx -t; then
systemctl reload nginx
echo "OK: Stopgap aktiv"
else
rm -f /etc/nginx/conf.d/php2shell.conf /etc/nginx/forge-conf/*/server/00-php2shell.conf
echo "nginx -t fehlgeschlagen, Änderungen entfernt"
exit 1
fi
Recipe „PHP2Shell Stopgap AUS“ (nach dem Patch)
#!/bin/bash
rm -f /etc/nginx/conf.d/php2shell.conf /etc/nginx/forge-conf/*/server/00-php2shell.conf
nginx -t && systemctl reload nginx && echo "Block entfernt"
Kontrolle, ob der Guard überall liegt: ls /etc/nginx/forge-conf/*/server/
Cloudflare WAF-Regel
Security → WAF → Custom rules → Create rule → Edit expression, Aktion Block, deployen. Im Free-Plan sind fünf eigene Regeln möglich. Die Regel blockt PHPSESSID in Cookie und Query (auch klein geschrieben und URL-codiert) sowie alle multipart/form-data-Anfragen:
(lower(url_decode(http.cookie)) contains "phpsessid") or (lower(url_decode(http.request.uri.query)) contains "phpsessid") or (any(lower(http.request.headers["content-type"][*])[*] contains "multipart/form-data"))
Ob die Regel greift, siehst du unter Security → Events. Und noch einmal: Das ersetzt den Block am Server nicht.
Testen
Von außen, auch mit PUT. Erwartet wird ein 403 vom Webserver. Mit --resolve deine-domain.at:443:DEINE-SERVER-IP prüfst du zusätzlich den direkten Weg am CDN vorbei:
curl -sS -o /dev/null -w '%{http_code}n' -F test=1 https://deine-domain.at/
curl -sS -o /dev/null -w '%{http_code}n' -X PUT -F test=1 https://deine-domain.at/index.php
Was nicht schützt
- WordPress-Sicherheitsplugins, auch die Firewall von Wordfence im erweiterten Modus – sie laufen erst, wenn PHP die Anfrage schon zerlegt hat.
file_uploads = Off– PHP liest den multipart-Body trotzdem.- Kleine Upload-Limits oder
disable_functions. - Maintenance-Modus in WordPress oder Laravel.
Nach dem Patch: richtig aktualisieren
- Logs sichern, bevor du patchst. Webserver- und PHP-Logs seit 20. Oktober kopieren. Die brauchst du für die Prüfung auf einen Einbruch.
- Prüfen, ob die Paketquelle den Fix schon hat. Unter Debian/Ubuntu:
sudo apt update, dannapt-cache policy php8.3-fpm. Distributionen portieren Fixes zurück, die Versionsnummer sieht deshalb oft „alt“ aus. Entscheidend ist der Changelog des Pakets. - Alle installierten PHP-Versionen aktualisieren, nicht nur die, auf die der
php-Befehl zeigt. Mitapt-mark showholdprüfen, ob ein Paket gesperrt ist – dann passiert beim Update stillschweigend nichts. - PHP-FPM und alle Dauerläufer neu starten: Queue-Worker, Horizon, Scheduler, Octane. Die laufen sonst mit dem alten Binary weiter. Übrig gebliebene Prozesse findest du mit
ls -l /proc/*/exe 2>/dev/null | grep -i 'php.*deleted'. - Docker-Images neu bauen und neu deployen. Ein laufender Container bekommt den Fix nicht automatisch.
- Blocks wieder entfernen (nginx, CloudPanel-Skript mit
off, Forge-Recipe „AUS“, Cloudflare-Regel deaktivieren) und Uploads sowie Formulare testen. Den Upload-Fortschritt kannst du ausgeschaltet lassen.
Prüfen, ob jemand schon drin war
Schau zurück bis zum Nachmittag des 20. Oktober – kurz davor wurde das Leak öffentlich:
- Logs nach auffälligen multipart-Anfragen und abgestürzten PHP-FPM-Workern durchsuchen.
- Neue oder geänderte Dateien im Webroot, im Upload-Ordner, in Plugins und
mu-pluginssuchen, z. B. mitfind /var/www -type f -newermt '2026-10-20 15:00 UTC'. .user.ini-Dateien undauto_prepend_fileauf Änderungen prüfen.- Cronjobs, systemd-Units und SSH-Keys auf neue Einträge kontrollieren.
- In WordPress und anderen Anwendungen nach unbekannten Admin-Konten schauen.
Findest du etwas: Server isolieren, Logs aufheben, neu aufsetzen und alle Zugangsdaten tauschen, die der PHP-Benutzer lesen konnte – wp-config.php, .env, Datenbank-Passwörter, API-Keys.
Meldepflicht in Deutschland, Österreich und der Schweiz
Wurde ein Server tatsächlich übernommen, waren meist auch personenbezogene Daten im Zugriff: Kundenkonten, Bestellungen, Formulareingaben. In Deutschland und Österreich greift dann Art. 33 DSGVO – Meldung an die zuständige Datenschutzbehörde innerhalb von 72 Stunden ab Kenntnis. In der Schweiz verlangt Art. 24 revDSG eine Meldung an den EDÖB „so rasch als möglich“. Deshalb ist die saubere Prüfung nach dem Patch kein Extra, sondern Pflicht.
Häufige Fragen
Ist meine WordPress-Seite von der PHP-Sicherheitslücke betroffen?
Wenn sie auf PHP läuft – und das tut jede WordPress-Seite –, solltest du davon ausgehen. Die Lücke sitzt in PHP selbst, nicht in WordPress. Ein WordPress-Update schließt sie nicht.
Reicht es, wenn mein Hoster patcht?
Bei Shared Hosting ja – aber frag nach, ob und wann der gepatchte Build für deine Domain aktiv ist. Bei mehreren PHP-Versionen im Panel heißt „Version umstellen“ nicht automatisch „gepatcht“.
Was ist mit PHP 7.4 oder 8.1?
Diese Versionen sind End of Life. Ein offizieller Fix ist nicht zu erwarten. Die Übergangsmaßnahmen müssen bleiben, bis die Seite auf eine unterstützte Version umgezogen ist.
Schützt mich ein Sicherheits-Plugin wie Wordfence?
Nein. Diese Plugins laufen erst, nachdem PHP die Anfrage verarbeitet hat. Für diese Lücke kommen sie zu spät.
Kann ich die Skripte einfach so ausführen?
Sie sind für gängige Ubuntu/Debian-Setups gedacht. Jeder Server ist anders – lies sie vorher durch, führe nginx -t aus und teste danach mit curl. Das CloudPanel-Skript und das Forge-Recipe rollen bei einem nginx-Fehler selbst zurück.
Du weißt nicht, auf welcher PHP-Version deine Seite läuft, oder willst das heute nicht selbst am Server machen? Schreib mir, ich schaue es mir mit dir an. Wer solche Updates nicht jedes Mal selbst verfolgen will, findet bei meiner WordPress-Wartung genau das: Updates, Kontrolle und jemand, der bei so einem Tag schon dran ist.
Quellen
- php.net: „Upcoming Critical PHP Security Release“ (20.10.2026)
- CERT-EU: Security Advisory 2026-018 „Critical Vulnerabilities in PHP“ (20.10.2026)
- Vincent Schmalbach: „CVE-2026-109618 and CVE-2026-109619: What you should do now“ (laufend aktualisiert, 21.10.2026)
- Sansec: „Critical PHP RCE: CVE-2026-109618 and CVE-2026-109619“ (21.10.2026)


