PHP2Shell, diese Woche
Am 21. Oktober 2026 hat das PHP-Projekt vier Releases auf einmal veröffentlicht, 8.5.12, 8.4.27, 8.3.36 und 8.2.35, um zwei kritische Lücken im Interpreter selbst zu schließen1. Nicht in WordPress. Nicht in einem Plugin. In PHP.
Beide sind mit 9,2 nach CVSS 4.0 bewertet. Beide erlauben Remote Code Execution ohne Login. Die Forscher, die sie gefunden haben, sagen klar, wie weit das reicht: „Every PHP version released in the last decade is affected by at least one of these vulnerabilities, going back to version 5.4.“2
Den Rest sagt das Advisory des PHP-Projekts selbst:
| Was das Advisory sagt | Was es für dich bedeutet |
|---|---|
| „unauthenticated remote code execution“ | niemand braucht ein Konto auf deiner Site |
| „risk highest for mod_php“ | das verbreitetste alte Apache-Setup steht am schlechtesten da |
| „before any application code runs“ | dein eigener Code, egal wie sorgfältig, hat nichts mitzureden |
| „There are no complete mitigations, updating is the only safe choice.“ | keine Konfigurationsänderung rettet dich |
| „PHP 8.1 and older no longer receive updates“ | ein großer Teil des Webs bekommt überhaupt keinen Fix |
Und es wurde schon benutzt, bevor irgendwer Bescheid bekam. Amazons Honeypot-Netz hat am 17. Oktober einen Versuch aufgezeichnet, vier Tage vor der Offenlegung3. watchTowr sah es am 21. in freier Wildbahn, und funktionierende Proofs of Concept waren wenige Stunden nach dem Patch öffentlich4.
Beide Bugs sind Speichersicherheitsfehler. Einer steckt darin, wie der Interpreter aufräumt, nachdem ihm der Speicher ausgegangen ist. Der andere ist ein Use-after-free: Speicher, der einer Anfrage gehört, wird freigegeben und danach wieder gelesen, und die nächste Anfrage auf demselben Worker kann ihn sehen56. Merk dir den zweiten. Er kommt später wieder.
Nichts davon ist neu. Genau darum geht es in diesem Beitrag. PHP2Shell ist kein Unfall, der einer sorgfältigen Sprache passiert ist. Es ist die neueste Seite in einer Bilanz von fast dreißig Jahren, und jede Zahl darin ist öffentlich.
Ein Prozess hält alles
Von November 2014 bis April 2017 war ich Third-Line-Linux-Engineer auf der Cloud- und Hosting-Plattform von Pulsant. Ein Teil des Jobs war, PHP-FPM-Umgebungen für E-Commerce-Kunden einzurichten und sie auf Geschwindigkeit zu trimmen.
PHP-Einbrüche waren an der Tagesordnung. Nicht gelegentlich. An der Tagesordnung. Und sie liefen auf zwei Ursachen hinaus: schlechter Betrieb und keine Trennung zwischen Frontend und Backend.
Die Sprache macht die zweite zum Normalfall. Eine typische PHP-Site ist ein Prozess. Das Seiten-Template, die Geschäftslogik und das SQL leben alle im selben Request-Handler, oft in derselben Datei. Dieser Prozess läuft als ein Betriebssystembenutzer. Er kann das Datenbankpasswort lesen, weil das Passwort in einer Datei neben dem Code liegt. Und er kann meistens in sein eigenes Web-Root schreiben, weil Uploads und Updates so funktionieren.
Das ist nicht meine Meinung darüber, wie PHP betrieben wird. Es ist das, was PHP und WordPress dokumentieren.
| Quelle | Was sie sagt |
|---|---|
| PHP-Handbuch, Apache-Modul | läuft PHP als Apache-Modul, dann „it inherits Apache’s user permissions“, und „a malicious script could access and modify the database, even without a username and password“7 |
| PHP-Handbuch, Apache-Installation | „The mod_php approach embeds PHP directly into every Apache httpd worker process.“8 |
| WordPress, wp-config | die Datei „is located in the root of your WordPress file directory and contains … database connection information“9 |
| WordPress, Dateirechte | wp-config.php „is initially created with 644 permissions, and it’s a hazard to leave it like that“10 |
| WordPress, Härtung | der Datenbankbenutzer „only needs“ SELECT, INSERT, UPDATE und DELETE, dann „it is NOT recommended to revoke these privileges“11 |
Lies die letzte Zeile noch einmal. Der Hersteller sagt dir, wie Least Privilege aussähe, und sagt dir dann, dass du es lassen sollst, weil Updates das Schema ändern.
Vergleich das mit der getrennten Variante. Das Frontend rendert Seiten und hält keine Geheimnisse. Das Backend ist ein eigener Dienst mit eigenem Benutzer, einer schmalen API und ohne Schreibrecht auf seinen eigenen Code. Das Datenbankkonto kann, was das Backend braucht, und sonst nichts. Die Empfehlungen von OWASP sagen dasselbe mit eigenen Worten: „The application’s backend database should be isolated from other servers“, in „a dedicated internal network segment“12. PHPs eigenes Handbuch sagt, Anwendungen „should never connect to the database as its owner or a superuser“13.
Nichts davon ist exotisch. So sieht ein ordentlicher Prozess aus. Warum es hier zählt, ist einfach. Im getrennten Modell bringt ein Bug im Frontend einem Angreifer ein Frontend. Im üblichen PHP-Modell bringt ihm ein Bug irgendwo die Templates, den Code, die Zugangsdaten und die Daten, alles auf einmal.
PHP-FPM hilft, und PHPs eigene Installationsanleitung nennt es inzwischen den empfohlenen Weg, PHP unter Apache zu betreiben8. Seine Pools können Worker „with different uid/gid/chroot/environment“ starten14. Aber ein Pool pro Site ist immer noch eine Site pro Prozess, mit allem, was diese Site hat. Es ist eine bessere Wand zwischen Kunden. Es ist keine Wand innerhalb der Anwendung.
Behalte dieses Bild durch jeden Abschnitt unten im Kopf. Jeder Bug in der Bilanz landet auf diesem Prozess.
Neunundzwanzig Jahre CVEs
Die National Vulnerability Database führt jede CVE gegen den PHP-Interpreter unter einer Produktkennung, cpe:2.3:a:php:php. Frag sie, und sie antwortet 75715.
Diese Zahl betrifft nur den Interpreter. Kein WordPress, kein Drupal, keine Plugins, keine Frameworks. Nur das Programm, das dein PHP ausführt.
| Zeitraum | CVEs | Speicherkorruption | Was los war |
|---|---|---|---|
| 1997 bis 2006 | 93 | 3 | frühes Web, kaum Klassifizierung |
| 2007 | 114 | 19 | der Month of PHP Bugs |
| 2008 bis 2014 | 187 | 54 | stetiges Grundrauschen |
| 2015 bis 2017 | 208 | 122 | die Jahre von unserialize und Speicherfehlern |
| 2018 bis 2023 | 100 | 63 | weniger, immer noch meist Speicher |
| 2024 bis 2026 | 55 | 27 | PHP2Shell fällt in dieses Fenster |
| Gesamt | 757 | 288 |
Zwei Spitzen fallen auf. Die erste ist März 2007, als ein ehemaliges Mitglied des PHP-Sicherheitsteams den Month of PHP Bugs veranstaltete und Lücken in der Zend Engine, im PHP-Kern und in seinen Erweiterungen „on a day by day basis“ offenlegte16. Er hatte das PHP Security Response Team gegründet, es dann verlassen und gesagt, warum: „I dislike the ways bugs are handled“17. Wenn der Gründer des Sicherheitsteams eines Projekts geht und jeden Tag einen Bug veröffentlicht, sagt dir das, wie es drinnen lief.
Die zweite Spitze ist 2016: 120 CVEs, 65 davon Speicherkorruption. Mehr dazu unten.
Die Speicherzahl ist eine Untergrenze, keine Schätzung. Die NVD markiert eine ganze Menge älterer Bugs als „Other“ statt mit einem Schwächetyp, darunter einige der Use-after-frees im nächsten Abschnitt. Die echte Zahl ist höher. Ich nehme die, die ich belegen kann.
Die Engine ist in C geschrieben
Hier muss das Argument zur Speichersicherheit sorgfältig gemacht werden, denn ein PHP-Entwickler wird völlig zu Recht darauf hinweisen, dass sein Code nie malloc aufruft. PHP-Skripte verwalten Speicher nicht von Hand. Du kannst in PHP keinen Pufferüberlauf so schreiben wie in C.
Musst du auch nicht. Der Interpreter, der dein Skript ausführt, ist in C geschrieben, und seine Erweiterungen sind in C geschrieben. Jedes Byte nicht vertrauenswürdiger Eingabe, das deine Site bekommt, jeder Header, jeder Upload, jedes Formularfeld, jedes Cookie, wird von diesem C geparst, bevor dein Code es sieht. Wenn dieses C falsch ist, spielt dein sorgfältiges PHP keine Rolle. PHP2Shell hat es bewiesen: Laut Advisory kann der Angriff „before any application code runs“ zünden1.
Die Bilanz zeigt, was dieses C falsch gemacht hat:
| CWE-Klasse | Was es ist | CVEs im PHP-Interpreter |
|---|---|---|
| CWE-119 | Speicherpufferfehler, allgemein | 93 |
| CWE-125 | Lesen außerhalb der Grenzen | 50 |
| CWE-190 | Ganzzahlüberlauf | 35 |
| CWE-189 | numerische Fehler, älteres Tag | 33 |
| CWE-416 | Use-after-free | 27 |
| CWE-787 | Schreiben außerhalb der Grenzen | 26 |
| CWE-476 | Nullzeiger-Dereferenzierung | 20 |
Genau diese Klassen meinen die Sicherheitsbehörden, wenn sie von Speichersicherheit reden. Im November 2022 riet die NSA Organisationen, „to consider making a strategic shift from programming languages that provide little or no inherent memory protection, such as C/C++, to a memory safe language when possible“18. Im Dezember 2023 hat die CISA, mit dem britischen National Cyber Security Centre unter den Mitautoren, eine Zahl daran gehängt: „two-thirds of reported vulnerabilities in memory unsafe programming languages still relate to memory issues“19.
Keines der Dokumente nennt PHP. Müssen sie auch nicht. Sie nennen die Sprache, aus der PHP gebaut ist.
Das schlimmste wiederkehrende Beispiel ist unserialize(), die Funktion, die einen gespeicherten String wieder in PHP-Objekte verwandelt. Sie hatte dieselbe Klasse von Bug an derselben Stelle mehr als einmal:
| CVE | Wo | Was die NVD festhält |
|---|---|---|
| CVE-2014-8142 | process_nested_data | Use-after-free in unserialize20 |
| CVE-2015-0231 | dieselbe Funktion | „exists because of an incomplete fix for CVE-2014-8142“21 |
| CVE-2015-2787 | Behandlung von __wakeup | Use-after-free in unserialize |
| CVE-2016-5771 | SPL, mit Garbage Collection | Use-after-free in unserialize22 |
| CVE-2016-5773 | ZipArchive, mit Garbage Collection | Use-after-free in unserialize |
Das PHP-Handbuch weiß es. Seine Seite zu der Funktion trägt die Warnung: „Do not pass untrusted user input to unserialize() regardless of the options value of allowed_classes.“23 Da sagt dir eine Sprache, dass eine ihrer eigenen eingebauten Funktionen nicht sicher ist für genau das, womit der meiste Web-Code den ganzen Tag umgeht.
Dann ist da PHP-FPM, der Prozessmanager, den PHPs eigene Installationsanleitung gegenüber mod_php empfiehlt. Im Oktober 2019 zeigte CVE-2019-11043, dass „in certain configurations of FPM setup it is possible to cause FPM module to write past allocated buffers … opening the possibility of remote code execution“24. Die fragliche Konfiguration war ein gängiges nginx-Setup. Behoben wurde es am 24. Oktober 201925. Die CISA nahm es später in ihren Katalog der nachweislich ausgenutzten Schwachstellen auf, markiert als in Ransomware-Kampagnen verwendet26.
Die PHP Foundation hat tatsächlich ein ordentliches Sicherheitsaudit des Interpreter-Quellcodes beauftragt, und das muss man ihr anrechnen. Die Ergebnisse, veröffentlicht am 10. April 2025, fanden 27 Probleme, 17 davon mit Sicherheitsrelevanz27. Das ist gute Praxis, und es sollte normal sein. Es sind aber auch 17 weitere, in einem Audit einer Codebasis, die schon fast drei Jahrzehnte öffentlicher Bug-Reports hinter sich hatte.
Die Sprache machte dieselben Fehler ein Stockwerk höher
Das C ist eine Schicht. Die Sprache darüber hat dieselbe Art Fehler in ihrem Design gemacht: Eingaben vertraut, denen sie nicht zu vertrauen hatte, und Jahre gebraucht, um damit aufzuhören.
| Feature | Was es tat | Standardmäßig aus oder veraltet | Entfernt | Dauer |
|---|---|---|---|---|
register_globals | machte Request-Parameter zu Skriptvariablen | aus in 4.2.0, 22. April 200228 | 5.4.0, 1. März 201229 | zehn Jahre |
| Magic Quotes | maskierte Eingaben automatisch, und falsch | veraltet in 5.3.0, 30. Juni 2009 | 5.4.0, 1. März 201230 | drei Jahre |
preg_replace /e | führte die Ersetzung als PHP-Code aus | veraltet in 5.5.0, 20. Juni 201331 | 7.0.0, 3. Dezember 201532 | zweieinhalb Jahre |
allow_url_include | ließ include Code über das Netz holen | veraltet in 7.4.033 | ||
| Phar-Metadaten | beim Dateizugriff automatisch deserialisiert | behoben in 8.034 | ||
0 == "foobar" | ergab true | behoben in 8.035 |
register_globals verdient eine eigene Zeile. Jahrelang wurde jeder Parameter in der Anfrage, sagen wir ?admin=1, zu einer Variable in deinem Skript, und wenn dein Code $admin prüfte, bevor er es gesetzt hatte, hatte der Angreifer es für dich gesetzt. Das PHP-Handbuch selbst nannte das Abschalten „the most controversial change in PHP“29. Zehn Jahre von standardmäßig aus bis weg. So lange hat das Projekt ein Feature geduldet, von dem es wusste, dass es gefährlich ist, weil das Entfernen Sites kaputt gemacht hätte.
Der Phar-Fall ist dasselbe Muster eine Schicht tiefer. 2018 zeigte Sam Thomas auf der Black Hat, dass ganz gewöhnliche Dateioperationen auf einem phar://-Pfad vom Angreifer gelieferte Metadaten deserialisierten, und damit das unserialize()-Problem in Funktionen brachten, die niemand für gefährlich hielt36. PHP 8.0 hörte Ende 2020 auf, das automatisch zu tun, „to fix potential security vulnerabilities due to object instantiation, autoloading, etc.“34.
Dann Type Juggling. PHPs == wandelt Typen vor dem Vergleich um, also werden Strings, die wie Zahlen aussehen, als Zahlen verglichen. Der RFC, der einen Teil davon in PHP 8.0 behoben hat, sagte es klar: „This results in many surprising comparison results, the most notable of which is that 0 == ‚foobar‘ returns true.“35
Der Fix war echt. Er war auch nur halb. Hier ist dieselbe Prüfung, ausgeführt in den offiziellen Containern php:7.4-cli und php:8.5-cli, Letzterer ist 8.5.12, das Release, das diese Woche gegen PHP2Shell gepatcht wurde, mit beiden Ausgaben nebeneinander:
$ php -r 'var_dump(0 == "foobar");'
bool(true) # 7.4.33
bool(false) # 8.5.12
$ php -r 'var_dump("0e462097431906509019562988736854" == "0e830400451993494058024219903391");'
bool(true) # 7.4.33
bool(true) # 8.5.12
Zwei verschiedene Strings, gleich. Beide fangen mit 0e und Ziffern an, also liest PHP beide als null mal zehn hoch irgendwas, und null ist gleich null. Beide haben die Form eines MD5-Hashes. Vergleich einen gespeicherten Passwort-Hash mit == statt mit === oder hash_equals(), und jede Eingabe, deren Hash zufällig so anfängt, passt. Das ist seit Jahren dokumentiert. Es funktioniert im neuesten Release immer noch.
Das ist die Sprache in einem Beispiel. Ein Fix, der reinging, die Hälfte des Problems zurückgelassen, und die sichere Variante setzt voraus, dass du weißt, dass es einen anderen Operator gibt.
Fast jedes Jahr eine Shell
Die Frage, die man jeder Plattform stellen sollte, ist nicht, wie viele Bugs sie hatte. Sondern wie oft jemand den ganzen Server übernehmen konnte, ohne Passwort und ohne dass irgendwer irgendwas anklickt.
Die NVD bewertet jede CVE. Filter die 757 nach der Bewertung, die genau das bedeutet, Angriff übers Netz, keine Rechte, keine Benutzerinteraktion, hohe Auswirkung auf Vertraulichkeit und Integrität, und du bekommst 17215.
172 verteilt auf 23 der 28 Jahre, in denen es überhaupt eine PHP-CVE gibt. Nur fünf sind leer. 2016 allein hat 65.
Eine Schweregradbewertung ist eine Einstufung, kein Einbruch. Die zweite Hälfte des Bildes ist deshalb der CISA-Katalog Known Exploited Vulnerabilities, der nur Lücken mit bestätigter Ausnutzung in freier Wildbahn listet26. Von seinen 1.754 Einträgen mit Stand 21. Oktober 2026 betreffen 81 PHP selbst oder in PHP geschriebene Anwendungen:
| Jahr der Aufnahme | PHP und PHP-Anwendungen | Ganzer Katalog |
|---|---|---|
| 2021 | 16 | 311 |
| 2022 | 16 | 555 |
| 2023 | 10 | 187 |
| 2024 | 8 | 186 |
| 2025 | 11 | 245 |
| 2026, bis 21. Oktober | 20 | 270 |
2026 ist schon jetzt das schlimmste Jahr für PHP im Katalog, und PHP2Shell ist noch gar nicht drin. Drei der diesjährigen stecken im WordPress-Kern selbst: zwei aufgenommen am 21. Juli und eine Remote File Inclusion am 25. September.
| KEV-Einträge, von denen bekannt ist, dass Ransomware sie nutzt | Was |
|---|---|
| CVE-2019-11043 | Pufferüberlauf in PHP-FPM |
| CVE-2024-4577 | Argument-Injection in PHP-CGI |
| CVE-2021-3129 | Laravel Ignition |
| CVE-2018-7600, CVE-2018-7602 | Drupal |
Und der Katalog zählt PHP viel zu niedrig. Er ist auf die Systeme der US-Bundesbehörden zugeschnitten und braucht eine CVE plus bestätigte Ausnutzung. Er enthält 3 Einträge zu WordPress-Plugins. Das WordPress-Plugin-Ökosystem verzeichnete allein 2025 11.334 Schwachstellen37. Die 81 sind der Teil, den jemand Offizielles aufgeschrieben hat.
WordPress vervielfacht es
WordPress macht 39,6 % aller Websites aus, und 58,3 % der Sites, deren Content-Management-System sich erkennen lässt38. PHP ist die serverseitige Sprache von 69,3 % der Sites, bei denen sich das sehen lässt39. Was auch immer PHPs Bilanz ist, WordPress trägt sie also in einen sehr großen Teil des Webs und legt dann seine eigene obendrauf.
Der Kern ist nicht das Hauptproblem. Die Plugins sind es.
| 2024 | 2025 | |
|---|---|---|
| Neue Schwachstellen im WordPress-Ökosystem, Patchstack | 7.96640 | 11.33437 |
| In Plugins | 96 % | 91 % |
| Im Kern | 7 | 6 |
| Bis zur Offenlegung nicht behoben | 33 % | 46 % |
| Median bis zur Massenausnutzung, stark ausgenutzte Bugs | 5 Stunden |
Wordfence zählte mit seiner eigenen Datenbank 8.223 für 2024, ein Anstieg um 68 % gegenüber 2023, und stellte fest: „Roughly 35% of the vulnerabilities disclosed in 2024 remain unpatched in 2025“41. Andere Datenbanken, andere Summen, gleiche Form.
Lass die Zahlen von 2025 einen Moment wirken. Fast die Hälfte der Schwachstellen hatte keinen Fix vom Entwickler, als sie öffentlich wurden. Und bei denen, auf die Angreifer tatsächlich losgehen, liegen im Median fünf Stunden zwischen Offenlegung und Massenausnutzung. Die meisten Leute prüfen ihre Plugin-Updates nicht alle fünf Stunden. Die meisten Leute können das gar nicht.
Das Plugin-Modell ist der Multiplikator. Die Sicherheit einer Site hängt vom unvorsichtigsten Autor von irgendetwas ab, das darauf installiert ist, und Wordfence fand heraus, dass „over one third of developers are unreachable or unresponsive“, wenn man ihnen eine Lücke meldet41. Patchstack zählte 1.614 Plugins und Themes, die 2024 wegen Sicherheitsproblemen, die niemand behob, aus dem Verzeichnis entfernt wurden40. Und wegen des Ein-Prozess-Modells läuft jedes Plugin mit den vollen Rechten der Site.
Die Vorfälle sind eine lange Liste. Das hier sind die mit Primärquellen dahinter:
| Jahr | Was | Ausmaß |
|---|---|---|
| 2011 | TimThumb, ein Bildskript, das in viele Themes gebündelt war, ließ Angreifer „upload and execute arbitrary PHP code“42 | „many commercial and free themes“ |
| 2014 | RevSlider, hinter der SoakSoak-Kampagne43 | „compromising over 100,000 WordPress sites“ |
| 2016 | Mossack Fonseca, die Kanzlei der Panama Papers: ihre Site „may have been breached via a vulnerable version of Revolution Slider“44 | die Site lief mit einer ausnutzbaren Version; wie die Daten abflossen, wurde nie gezeigt |
| 2017 | Content-Injection über die REST-API in WordPress 4.7.0 und 4.7.1, standardmäßig aktiv45 | 66.000 verunstaltete, von Google indexierte Seiten laut Sucuri46; 1.893.690 laut Wordfence vier Tage später47 |
| 2020 | WP File Manager, Codeausführung ohne Anmeldung, ausgenutzt, bevor es einen Patch gab48 | „over 700,000 active installations“ |
| 2025 | SureTriggers, Anlegen von Admin-Konten ohne Anmeldung49 | „exploitation attempts observed within hours after disclosure“ |
Bei der Zeile von 2016 war ich vorsichtig. Wordfence zeigte, dass die Site der Kanzlei eine Slider-Version fuhr, die trivial ausnutzbar war. Es zeigte nicht, dass die Dokumente auf diesem Weg abgezogen wurden, und ich werde nicht mehr behaupten, als die Belege hergeben.
Wie die Malware bleibt
Reinkommen ist die eine Hälfte. Drinbleiben ist die andere, und PHP macht das leicht, aus einem Grund, der direkt auf das Ein-Prozess-Bild zurückgeht.
Der Interpreter führt jede .php-Datei aus, die er erreichen kann. Das Web-Root ist meist von demselben Benutzer beschreibbar, der den Code ausführt. Sobald ein Angreifer also irgendeinen Weg hat, eine Datei zu schreiben, ein Upload-Formular, einen Plugin-Bug, einen Dateimanager, kann er ein Skript schreiben, das jedes Mal läuft, wenn jemand es aufruft. Das ist eine Web-Shell: eine kleine Datei, die in deiner Site sitzt und Befehle annimmt.
Die CISA sagt seit Jahren, in welchen Sprachen die meistens geschrieben sind: „The most commonly observed web shells are written in languages that are widely supported, such as PHP and ASP.“50 Die gemeinsame Empfehlung von NSA und Australian Signals Directorate nennt sie „a long-standing, pervasive threat that continues to evade many security tools“, und schwer zu erkennen, weil sie „easily modified by attackers and often employ encryption, encoding, and obfuscation“ sind51.
Die Zahlen aus den Bereinigungen zeigen, wie oft sie da sind:
| Quelle | Befund |
|---|---|
| Sucuri, 2022, 43.374 Sites bereinigt | „69.63% of compromised websites were found to have at least one backdoor“; 1.188.864 Hintertüren entfernt52 |
| Sucuri, 2022 | „90% of credit card skimmers were found in the form of malicious PHP code“52 |
| Sucuri, 2023, 39.594 Sites bereinigt | „49.21% of compromised websites were found with at least one website backdoor“; WordPress 95,5 % der Infektionen53 |
| Wordfence, 2024 | „just under one million distinct sites infected with malware“41 |
Im jüngsten Bereinigungsjahr hatte also die Hälfte der gehackten Sites noch einen Weg zurück auf der Platte liegen. Stell die Datenbank wieder her, patche das Plugin, und der Angreifer spaziert durch die Datei wieder rein, die er dagelassen hat.
Dafür gibt es keinen cleveren Fix. Es gibt den langweiligen, ordentlichen, und die NSA hat ihn aufgeschrieben: „web applications should not have permission to write directly to a web accessible directory or modify web accessible code“51. Dieser eine Satz ist das Schichtenmodell vom Anfang dieses Beitrags, gesagt von einem Nachrichtendienst.
| Wo es schiefgeht | Die Maßnahme, die es stoppt |
|---|---|
| der Laufzeitbenutzer kann den Code schreiben | Code gehört einem eigenen Deploy-Benutzer, für den Laufzeitbenutzer nur lesbar |
| Uploads landen im Web-Root | Uploads „outside of the webroot“ ablegen, oder auf einem anderen Server54 |
| PHP führt alles in den Uploads aus | keine Skriptausführung für Upload-Pfade im Webserver, und „disable per directory configuration overrides on upload directories“54 |
| niemand bemerkt eine neue Datei | Dateiintegritätsüberwachung gegen eine bekannt gute Kopie51 |
| das Datenbankkonto darf alles | Least Privilege für den Datenbankbenutzer13 |
WordPress’ Härtungsanleitung erwähnt, wenn’s interessiert, überhaupt nicht, dass man PHP im Upload-Verzeichnis an der Ausführung hindern sollte11. Deshalb zitiert die Tabelle stattdessen OWASP und die NSA.
Schau, was nicht in dieser Tabelle steht. PHPs eigene Härtungseinstellungen. Das Handbuch ist da ehrlich. disable_functions „can be circumvented and should not be considered a sufficient security measure for shared hosting environments“, und open_basedir „is just an extra safety net, that is in no way comprehensive, and can therefore not be relied upon when security is needed“55. Wenn die eigene Dokumentation einer Sprache dir sagt, dass ihre Sicherheitsschalter keine Sicherheitsgrenzen sind, dann glaub ihr. Die Grenze muss deshalb von außerhalb des Prozesses kommen.
Sogar bei php.net wurde eingebrochen
Wäre die Infrastruktur des Projekts selbst solide, könnte man argumentieren, die Bilanz gehe auf ein schweres Problem zurück, das gut gehandhabt wurde. Es wurde zweimal eingebrochen.
| Wann | Was passiert ist |
|---|---|
| 22. bis 24. Oktober 2013 | „JavaScript malware was served to a small percentage of php.net users“; „two servers were compromised“, Methode „unknown at this time“56 |
| 28. März 2021 | „two malicious commits were pushed to the php-src repo“ unter den Namen zweier Core-Entwickler57 |
Der von 2021 ist der, der zählt. Jemand hat Code in den Quellbaum der Sprache selbst geschoben und sich dabei als die Leute ausgegeben, die sie pflegen. Es wurde entdeckt. Die Antwort des Projekts ist zitierwürdig, weil sie die richtige ist, klar gesagt: „maintaining our own git infrastructure is an unnecessary security risk“, und die Repositories zogen zu GitHub um57.
Ehre, wem Ehre gebührt: Das war eine gute Entscheidung, schnell getroffen und offen erklärt. Aber schau, was sie eingesteht. Jahrelang lag die maßgebliche Quelle einer Sprache, die den Großteil des Webs betreibt, auf selbst betriebener Infrastruktur, die das Projekt selbst für ein Risiko hielt, das es nicht tragen sollte.
Das halbe Web läuft auf einer Version, die niemand patcht
Alles oben setzt voraus, dass die Site aktuell ist. Sehr viele sind es nicht.
php.net unterstützt derzeit vier Zweige. 8.2 bekommt nur noch Sicherheitsfixes, bis 31. Dezember 2026. 8.3, 8.4 und 8.5 sind der Rest58. Alles Ältere ist End of Life: 8.1 seit 31. Dezember 2025, 8.0 seit November 2023, 7.4 seit November 202259.
Jetzt der gemessene Anteil dessen, was tatsächlich läuft:
| Heute ohne Support | Ohne Support ab 1. Januar 2027 | |
|---|---|---|
| PHP-Sites, W3Techs6061 | 48,3 % | etwa 66 % |
| WordPress-Installationen, wordpress.org62 | 34,7 % | etwa 58 % |
PHP 7.4 allein, seit fast vier Jahren ohne Support, macht etwa ein Fünftel aller PHP-Sites aus, die ihre Version zeigen. Die Anforderungsseite von WordPress verlangt PHP 8.3 und sagt dann, WordPress „also works with PHP 7.4+“, während sie anmerkt, dass diese Versionen „have reached their official End Of Life“63. Ein Hersteller, der weiter auf einer toten Version läuft, ist ein Hersteller, der beschlossen hat, dich nicht zum Umzug zu bewegen.
Zwei ehrliche Einschränkungen. W3Techs sieht die Version nur auf Sites, die sie mitteilen. Und manche Linux-Distributionen portieren Fixes in alte PHP-Builds zurück, also heißt „von php.net nicht unterstützt“ nicht immer „ungepatcht“. Aber PHP2Shell ist genau der Test dafür. Das Projekt hat diesmal Quell-Patches für 7.4, 8.0 und 8.1 veröffentlicht1, und irgendwer muss sie trotzdem bauen, ausliefern und installieren. Auf einem Shared Host mit einer Version, die niemandem gehört, ist dieser Irgendwer niemand.
Ich habe PHP aufgegeben. Du solltest auch über den Ausstieg nachdenken.
Ich habe früher PHP geschrieben. Nach Pulsant habe ich die Sprache aufgegeben, wegen der Probleme, die sie verursacht hat, und der Arbeit, die diese Probleme gemacht haben. Kein einzelner schlimmer Vorfall. Jahre derselben zwei Ursachen, Site für Site, und die Aufräumarbeit landete bei dem, der gerade Schicht hatte.
Also sage ich es klar. Wenn du die Wahl hast, schau dir an, wie du davon wegkommst. Es gibt inzwischen bessere Werkzeuge dafür, und Go ist das, auf das ich dich zuerst verweisen würde.
Nicht weil es gerade in Mode ist. Sondern weil es standardmäßig das meiste von dem entfernt, was dieser Beitrag gezählt hat:
| Die übliche PHP-Site | Ein Go-Dienst | |
|---|---|---|
| Speichersicherheit | Engine in C geschrieben, 288 CVEs mit Speicherkorruption | speichersicher by Design; NSA und CISA nennen es beide1819 |
| Ausführung des Codes | bei jeder Anfrage neu geparst und kompiliert, außer OPcache ist geladen, eine Erweiterung, die du vor 8.5 selbst hinzufügst; dann ausgeführt von einem in C geschriebenen Interpreter; ein JIT seit 8.0, standardmäßig aus6465 | einmal kompiliert, vorab, zu nativem Maschinencode66 |
| Bedienen einer Anfrage | der Webserver reicht jede Anfrage an einen Interpreter weiter | ein kompiliertes Binary beantwortet HTTP selbst |
| Eine im Web-Root abgelegte Datei | eine .php-Datei läuft, sobald jemand sie aufruft | nichts führt eine Datei von der Platte wegen ihres Pfads aus |
| HTML-Ausgabe | echo schreibt roh; Maskieren ist eine Funktion, an die du denken musst | html/template maskiert standardmäßig, je nach Kontext67 |
| SQL | Prepared Statements gibt es in PDO, wenn du sie benutzt | der dokumentierte Weg übergibt Parameter als Argumente68 |
| Bekannte Lücken in deinen Abhängigkeiten | aus den Nachrichten erfahren | govulncheck meldet nur die, die dein Code tatsächlich aufruft69 |
| Wo die Teile liegen | Code, Konfiguration und Uploads in einem beschreibbaren Baum | ein schreibgeschütztes Binary, Konfiguration und Uploads woanders |
Kompiliert zählt doppelt. Es ist schneller: Go-Programme „are compiled ahead of time to native machine code“, ohne virtuelle Maschine darunter, und eines der erklärten Designziele ist „to approach the performance of C for comparable programs“66. Und es ist sicherer, weil kein Interpreter im Request-Pfad zur Laufzeit Code parst und keine C-Engine mit 757 CVEs zwischen dem Netz und deinem Programm steht. PHP macht, sich selbst überlassen, das Gegenteil. Ohne OPcache lädt, parst und kompiliert es jedes Skript bei jeder Anfrage, unnötig, tausende Male pro Minute auf einer gut besuchten Site. OPcache gibt es, um genau das zu verhindern, „removing the need for PHP to load and parse scripts on each request“64. Aber es ist ab Werk nicht an. Bis einschließlich 8.4 ist es eine separate Shared Extension, die jemand mit zend_extension laden und konfigurieren muss. Erst PHP 8.5 baut es fest ein: „The Opcache extension is now always built into the PHP binary and is always loaded“70. Der eigene RFC des Projekts zu dieser Änderung sagt „running PHP in production without OPcache is generally considered a mistake“71. W3Techs sieht 8.5 auf 4,5 % der PHP-8-Sites60, also ist für fast alles, was heute läuft, die Lösung gegen das Kompilieren jedes Skripts bei jeder Anfrage immer noch ein Zusatz, an den jemand denken musste. Und selbst geladen ist das, was es cacht, Bytecode, den der C-Interpreter ausführt. Go erledigt das Kompilieren einmal, bevor das Programm überhaupt eine Anfrage sieht.
Schneller und sicherer, vorausgesetzt, es ist ordentlich programmiert. Diese letzte Bedingung ist der ganze Inhalt der nächsten Absätze.
Gos Template-Paket fasst sein Design in einem Satz: Es erzeugt „HTML output safe against code injection“, und „The escaping is contextual, so actions can appear within JavaScript, CSS, and URI contexts.“67 Sein Datenbank-Leitfaden ist genauso klar: „You can avoid an SQL injection risk by providing SQL parameter values as sql package function arguments.“68 Das sind die Standards. In PHP sind das Dinge, von denen du wissen musst, dass du sie dir holen musst.
Die Zeile, die ich unterstreichen würde, ist die abgelegte Datei. Die Hälfte der gehackten Sites, die Sucuri 2023 bereinigt hat, hatte noch eine Hintertür auf der Platte53, und das funktioniert nur, weil der Interpreter jedes Skript ausführt, das er erreichen kann. Ein kompilierter Dienst sucht nicht nach Skripten. Da ist nichts, woran eine abgelegte Datei andocken könnte.
Jetzt der ehrliche Teil, denn eine Sprache ist kein Heilmittel. Go ist speichersicherer, nicht perfekt speichersicher. Sein eigenes Speichermodell sagt, ein Data Race auf einem Slice, einer Map oder einem Interface-Wert „can in turn lead to arbitrary memory corruption“72, und Go liefert das Werkzeug mit, um das zu fangen. Bau mit -race oder führ go test -race aus, und das Binary wird mit einem Detektor kompiliert, der ein Race in dem Moment meldet, in dem es passiert. Er fängt Races zur Laufzeit statt zur Kompilierzeit und „can’t find races in code paths that are not executed“, also gehört er in jeden Testlauf und unter realistische Last73. PHP hat nichts dergleichen. Den Speicher einer Anfrage von der nächsten fernzuhalten, bleibt komplett der Engine überlassen, und PHP2Shell ist genau diese Engine, die es falsch macht: Speicher, freigegeben von einer Anfrage, gelesen von der nächsten auf demselben Worker6. Abgesehen davon stoppt Go die Klasse der Speicherkorruption, die dieser Beitrag gezählt hat, und macht bei zwei weiteren den sicheren Weg zum einfachen. Es stoppt keine kaputte Login-Prüfung, keinen fehlenden Berechtigungstest und keine Abfrage, die aus zusammengeklebten Strings gebaut wird, wenn du darauf bestehst. Go veröffentlicht auch eigene Sicherheits-Advisories, über seine Schwachstellendatenbank69. Und ein Go-Dienst, der als root aus einem beschreibbaren Verzeichnis läuft, ist immer noch schlecht betrieben.
Was es ändert, ist der Standard. PHPs Standard ist ein Prozess, der alles hält. Gos Standard ist ein Programm, das eine Aufgabe erledigt, und das ist die Trennung vom Anfang dieses Beitrags, mit dem Großteil der Arbeit schon erledigt. Wenn Go nicht zu deinem Team passt, ist Rust der andere Ausweg. Beide werden vorab in nativen Maschinencode kompiliert. Rust läuft „with no runtime or garbage collector“74, und Compiler und Laufzeit von Go sind seit Go 1.5 „implemented in Go and assembler, without C“75.
C# und Java stehen ebenfalls auf der Liste speichersicherer Sprachen der Behörden18, aber sie sind kein Ausweg aus dem Problem, mit dem dieser Beitrag angefangen hat. Beide laufen auf einer virtuellen Maschine, die in C++ geschrieben ist. HotSpot von OpenJDK umfasst „around 3000 C/C++ header and source files, comprising more than 1.2 million lines of code“76, und Garbage Collector und JIT-Compiler von .NET sind C++-Quellcode im CoreCLR-Baum77. Das ist dieselbe Form wie bei PHP: eine große native Engine zwischen dem Netz und deinem Code. Und Java lädt Code absichtlich in eine laufende Anwendung nach. Sein Standard-Classloader ist dazu da, „to load classes and resources from a search path of URLs referring to both JAR files and directories“78, und Log4Shell hat daraus Remote Code Execution gemacht: Wer eine Logmeldung kontrollierte, „can execute arbitrary code loaded from LDAP servers“79. Die Lücke landete direkt im Katalog der CISA26. Es ist dieselbe Tür wie bei PHP, nur mit mehr Zeremonie davor.
Also nimm Go oder Rust. Zieh zuerst das Backend um, einen Endpunkt nach dem anderen, und lass das PHP-Frontend nichts halten, was sich zu stehlen lohnt, bis es auch gehen kann.
Wenn du es immer noch so ausrollst, kannst du dich dann Profi nennen?
Oben steht genug Beweismaterial, dass das keine Meinung mehr ist. Also hier die Frage, direkt gestellt. Wenn du PHP immer noch als einen Prozess ausrollst, der den Code, die Zugangsdaten und ein beschreibbares Web-Root hält, kannst du dich dann Profi nennen?
Es kommt darauf an, welcher von drei Leuten du bist. Und zu wissen, welcher, ist nichts, was dir passiert. Dafür zu sorgen, dass du es weißt, ist der Job.
Du hast eine echte Einschränkung, und du hast sie aufgeschrieben. Ein Produkt, von dem das Geschäft abhängt, gibt es nur in PHP. Eine Migration ist kalkuliert und steht im Budget fürs nächste Jahr. Gut. Das ist professionell, vorausgesetzt, der Grund steht auf Papier mit einem Datum daneben, der Laufzeitbenutzer kann den Code nicht schreiben, Uploads können nicht ausgeführt werden, das Datenbankkonto ist zurechtgestutzt, und du hast diese Woche PHP2Shell gepatcht. Du fährst ein bekanntes Risiko mit Absicht, mit den Wänden, die du drumherum ziehen kannst.
Es hat dir nie jemand gesagt. Niemand hat dir die Bilanz gezeigt, und das Tutorial, aus dem du gelernt hast, hat alles in ein Verzeichnis gepackt. Das ist eine Lücke, und jeder hat Lücken. Es hört auf, eine Lücke zu sein, in dem Moment, in dem du bis hierher gelesen hast.
Du weißt es und baust es trotzdem so. Du hast die Zahlen gesehen, oder genug davon. Du weißt, dass das Datenbankpasswort im Web-Root liegt und das Web-Root beschreibbar ist. Du rollst es so aus, weil es schneller geht, weil der Kunde nicht für Besseres zahlt, und weil niemand dich gezwungen hat, es zu rechtfertigen. Auf diesen Fall zielt die Frage. Das Versagen ist nicht die Lücke in deinem Wissen. Es ist, über eine Lücke hinwegzubauen, die du schon gesehen hast und nie zurückgegangen bist, um sie zu schließen.
Jeder war mal da. Aus freien Stücken dort zu bleiben, ist der Teil, der sich nicht verteidigen lässt.
Die Tür stand immer offen
Was mir beim Lesen dieser Bilanz auffällt, ist nicht, dass PHP Bugs hat. Jede Sprache hat welche. Sondern wie wenig davon je eine Überraschung war.
Das Projekt wusste 2002, dass register_globals gefährlich ist, und hat es 2012 entfernt. Sein Handbuch sagt dir, du sollst unserialize() nicht trauen, disable_functions nicht trauen, open_basedir nicht trauen. Seine eigene Dokumentation sagt, ein Skript unter mod_php kann ohne Passwort an die Datenbank. Die Behörden sagen seit Jahren, dass die Sprache, aus der es gebaut ist, die Quelle von zwei Dritteln der Speicherfehler ist. Jede Warnung ist da, schriftlich, von den Leuten, die es wissen müssten.
Und es hat trotzdem immer weiter gewonnen, weil es billig war. Billig zu hosten, billig zu lernen, billig an einen Kunden zu verkaufen, der bis Freitag eine Website wollte. Ein Verzeichnis, ein Prozess, ein Passwort in einer Datei, und eine Site, die lief. Der Preis war ein Shared-Hosting-Tarif. Was es gekostet hat, stand nie auf der Rechnung: die Aufräumarbeiten, die Hintertüren auf der Platte, die Kartennummern der Kunden, abgegriffen von bösartigem PHP, das Fünf-Stunden-Fenster zwischen Offenlegung und Angriff.
Das ist der Teil, für den ich keine Geduld habe. Nicht die Bugs. Die Entscheidung, immer und immer wieder getroffen von Leuten, die es besser wussten, dass der billige Weg gut genug war, weil niemand nachgeschaut hat. Ein Standard ist das, was du einhältst, wenn niemand nachschaut. Die Trennung zwischen Frontend und Backend, der schreibgeschützte Code, das zurechtgestutzte Datenbankkonto: Nichts davon ist neu, nichts davon ist teuer, und all das hätte einen guten Teil der Vorfälle oben zu nichts gemacht, worüber man schreiben müsste.
PHP2Shell ist nicht das Ende dieser Bilanz. Es ist nur der Eintrag dieser Woche. Die Sprache wird es patchen, die Hoster werden das Update irgendwann ausrollen, und der Versionsanteil wird nach oben driften, wie er es immer tut, langsam. Ob dich der nächste etwas kostet, entscheidet nicht PHP. Sondern ob du die Wände gebaut hast, die es dir nie gegeben hat, oder zu etwas umgezogen bist, das sie mitbringt.
PHP — News archive 2026, 21st October — „PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35 fix two critical vulnerabilities that can allow unauthenticated remote code execution“; „We consider the risk highest for mod_php, with a demonstrated exploit where an unauthenticated request can trigger the attack before any application code runs“; „There are no complete mitigations, updating is the only safe choice.“ ↩︎ ↩︎ ↩︎
Wiz Research — PHP2Shell — 21. Oktober 2026; „Every PHP version released in the last decade is affected by at least one of these vulnerabilities, going back to version 5.4“; „All of the disclosed vulnerabilities are memory-safety issues“. ↩︎
AWS Security Blog — PHP2Shell exploitation prior to public disclosure in MadPot — ein Ausnutzungsversuch, aufgezeichnet am 17. Oktober 2026. ↩︎
watchTowr — PHP2Shell FAQ — Ausnutzung in freier Wildbahn beobachtet am 21. Oktober 2026. ↩︎
NVD — CVE-2026-109618 — die Fehlerbehandlung bei Speichermangel hinterlässt teilweise initialisierte Request-Daten, die das Aufräumen für gültig hält; Remote Code Execution. ↩︎
NVD — CVE-2026-109619 — Request-Speicher wird benutzt, nachdem er freigegeben wurde; Remote Code Execution; betroffen ab 5.4.0. ↩︎ ↩︎
PHP manual — Installed as an Apache module — „When PHP is used as an Apache module it inherits Apache’s user permissions“; „a malicious script could access and modify the database, even without a username and password“. ↩︎
PHP manual — Apache 2.x on Unix systems — „The mod_php approach embeds PHP directly into every Apache httpd worker process.“ ↩︎ ↩︎
WordPress — wp-config.php — liegt im Wurzelverzeichnis von WordPress und enthält die Verbindungsdaten der Datenbank. ↩︎
WordPress — Changing file permissions — wp-config.php „is initially created with 644 permissions, and it’s a hazard to leave it like that“. ↩︎
WordPress — Hardening WordPress — Datenbankrechte, Dateirechte; keine Anleitung, wie man die PHP-Ausführung in Uploads blockiert. ↩︎ ↩︎
OWASP — Database Security Cheat Sheet — „The application’s backend database should be isolated from other servers“; ein eigenes internes Netzsegment. ↩︎
PHP manual — Database design — „Applications should never connect to the database as its owner or a superuser.“ ↩︎ ↩︎
PHP manual — FastCGI Process Manager — Pools, die Worker „with different uid/gid/chroot/environment“ starten. ↩︎
NVD CVE API,
virtualMatchString=cpe:2.3:a:php:php— abgefragt am 23. Oktober 2026: 757 CVEs. Als Speicherkorruption gezählt: CWE-119, 120, 121, 122, 125, 129, 131, 189, 190, 191, 415, 416, 476, 680, 787, 824, 843 oder 908: 288. Als vollständige Fernübernahme gezählt: CVSS 3.xAV:N/PR:N/UI:N/C:H/I:H, oder CVSS 2 Netzwerk, keine Authentifizierung, vollständige Auswirkung auf Vertraulichkeit und Integrität, wo es keine 3.x-Bewertung gibt: 172. ↩︎ ↩︎Month of PHP Bugs, php-security.org, Wayback Machine — „During March 2007 old and new security vulnerabilities in the Zend Engine, the PHP core and the PHP extensions will be disclosed on a day by day basis.“ ↩︎
The Register — Stefan Esser interview, 7th February 2007 — Gründer des Hardened-PHP Project, hatte kurz zuvor das PHP Security Response Team verlassen: „I dislike the ways bugs are handled“. ↩︎
NSA — Software Memory Safety, November 2022, Wayback Machine — „a strategic shift from programming languages that provide little or no inherent memory protection, such as C/C++, to a memory safe language when possible.“ Außerdem: „Examples of memory safe language include C#, Go, Java®, Ruby™, Rust®, and Swift®.“ ↩︎ ↩︎ ↩︎
CISA and partners — The Case for Memory Safe Roadmaps, December 2023 — unter anderem mit dem britischen NCSC als Mitautor; „two-thirds of reported vulnerabilities in memory unsafe programming languages still relate to memory issues.“ ↩︎ ↩︎
NVD — CVE-2014-8142 — Use-after-free in
process_nested_databeim Deserialisieren. ↩︎NVD — CVE-2015-0231 — Use-after-free in unserialize, das „exists because of an incomplete fix for CVE-2014-8142“. ↩︎
NVD — CVE-2016-5771 — Use-after-free in SPL, ausgelöst über unserialize und Garbage Collection. ↩︎
PHP manual — unserialize — „Do not pass untrusted user input to unserialize() regardless of the options value of allowed_classes.“ ↩︎
NVD — CVE-2019-11043 — „in certain configurations of FPM setup it is possible to cause FPM module to write past allocated buffers … opening the possibility of remote code execution.“ ↩︎
PHP 7 ChangeLog — behoben am 24. Oktober 2019 in 7.3.11, 7.2.24 und 7.1.33, Bug #78599. ↩︎
CISA — Known Exploited Vulnerabilities catalogue — JSON-Feed Version 2026.10.21, 1.754 Einträge; 81 für PHP oder in PHP geschriebene Anwendungen nach Hersteller und Produkt; Ransomware-Nutzung wie im Feed vermerkt. ↩︎ ↩︎ ↩︎
The PHP Foundation — PHP core security audit results, 10th April 2025 — „The audit identified 27 issues, with 17 having security implications“. ↩︎
PHP 4 ChangeLog — 4.2.0, 22. April 2002: „register_globals defaults to ‘off’ now“. ↩︎
PHP manual — Using Register Globals, Wayback Machine — „DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0“; „the most controversial change in PHP“. ↩︎ ↩︎
PHP manual — Magic Quotes, Wayback Machine — „DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 5.4.0“. ↩︎
PHP manual — Deprecated features in PHP 5.5.x, Wayback Machine — „The preg_replace() /e modifier is now deprecated.“ ↩︎
PHP manual — Pattern Modifiers, Wayback Machine —
e„DEPRECATED in PHP 5.5.0, and REMOVED as of PHP 7.0.0.“ ↩︎PHP manual — Deprecated features in PHP 7.4 — „The allow_url_include ini directive is deprecated.“ ↩︎
PHP manual — Backward incompatible changes in PHP 8.0 — Phar-Metadaten „will no longer be automatically unserialized, to fix potential security vulnerabilities due to object instantiation, autoloading, etc.“ ↩︎ ↩︎
PHP RFC — Saner string to number comparisons — umgesetzt in PHP 8.0; „the most notable of which is that 0 == ‚foobar‘ returns true.“ ↩︎ ↩︎
Sam Thomas, Black Hat USA 2018 — It’s A PHP Unserialization Vulnerability Jim, But Not As We Know It — Dateioperationen auf
phar://-Pfaden deserialisieren Metadaten. ↩︎Patchstack — State of WordPress Security in 2026 — Daten für 2025: 11.334 neue Schwachstellen, 91 % in Plugins, 6 im Kern, 46 % bis zur Offenlegung nicht behoben, Median 5 Stunden bis zur Massenausnutzung. ↩︎ ↩︎
W3Techs — WordPress — „58.3% of all the websites whose content management system we know. This is 39.6% of all websites.“ ↩︎
W3Techs — PHP — „PHP is used by 69.3% of all the websites whose server-side programming language we know.“ Abgelesen am 23. Oktober 2026. Hauptversionen unter PHP-Sites: 8 bei 65,3 %, 7 bei 26,9 %, 5 bei 7,7 %. ↩︎
Patchstack — State of WordPress Security in 2025 — Daten für 2024: 7.966 neue Schwachstellen, 96 % in Plugins, 7 im Kern, 33 % bis zur Offenlegung nicht behoben. ↩︎ ↩︎
Wordfence — 2024 Annual WordPress Security Report — 8.223 Schwachstellen, ein Anstieg um 68 %; „Roughly 35% of the vulnerabilities disclosed in 2024 remain unpatched in 2025“; „just under one million distinct sites infected with malware“. ↩︎ ↩︎ ↩︎
Mark Maunder — Zero day vulnerability in many WordPress themes, 1st August 2011 — timthumb.php gebündelt mit „many commercial and free themes“; Angreifer konnten „upload and execute arbitrary PHP code“. ↩︎
Sucuri — RevSlider vulnerability leads to massive WordPress SoakSoak compromise, 15th December 2014 — „compromising over 100,000 WordPress sites“. ↩︎
Wordfence — Mossack Fonseca breach, Revolution Slider possible cause, 7th April 2016, Wayback Machine — „may have been breached via a vulnerable version of Revolution Slider“. ↩︎
Sucuri — Content injection vulnerability in WordPress REST API, 1st February 2017 — „allows an unauthenticated user to modify the content of any post or page“; standardmäßig aktiv in 4.7.0 und 4.7.1. ↩︎
Sucuri — WordPress REST API vulnerability abused in defacement campaigns, 6th February 2017 — „Google alone shows 66,000+ pages compromised“, für eine einzelne Kampagne. ↩︎
Wordfence — Rapid growth in REST API defacements, 10th February 2017, Wayback Machine — von Google indexierte verunstaltete Seiten wuchsen „from 1,496,020 to 1,893,690“; Sucuris frühere Zählung lag bei 66.000. ↩︎
Wordfence — 700,000 WordPress users affected by zero-day in File Manager plugin, 1st September 2020, Wayback Machine — „a WordPress plugin with over 700,000 active installations“. ↩︎
Patchstack — SureTriggers vulnerability exploited within 4 hours, 10th April 2025 — Anlegen eines Administrators ohne Anmeldung; „exploitation attempts observed within hours after disclosure“. ↩︎
CISA — Compromised Web Servers and Web Shells, TA15-314A — „The most commonly observed web shells are written in languages that are widely supported, such as PHP and ASP.“ ↩︎
NSA and ASD — Detect and Prevent Web Shell Malware, April 2020, Wayback Machine — „web applications should not have permission to write directly to a web accessible directory or modify web accessible code“; Dateiintegritätsüberwachung als Rückfallebene. ↩︎ ↩︎ ↩︎
Sucuri — 2022 Website Threat Research Report — 43.374 Sites bereinigt; 69,63 % mit mindestens einer Hintertür; 1.188.864 Hintertüren entfernt; 90 % der Kartenskimmer in bösartigem PHP. ↩︎ ↩︎
Sucuri — 2023 Hacked Website and Malware Threat Report — 39.594 Sites bereinigt; 49,21 % mit mindestens einer Hintertür; WordPress 95,5 % der Infektionen. ↩︎ ↩︎
OWASP — File Upload Cheat Sheet — Uploads „outside of the webroot“ ablegen; „disable per directory configuration overrides on upload directories“. ↩︎ ↩︎
PHP manual — Description of core php.ini directives —
disable_functions„can be circumvented“;open_basedir„can therefore not be relied upon when security is needed“. ↩︎PHP — News archive 2013, 24th October — Malware ausgeliefert vom 22. bis 24. Oktober 2013; zwei Server kompromittiert. ↩︎
PHP internals — Changes to Git commit workflow, 28th March 2021 — zwei bösartige Commits nach php-src geschoben; der Server git.php.net eingestellt und GitHub maßgeblich gemacht. ↩︎ ↩︎
PHP — Supported versions — 8.2 Sicherheitsfixes bis 31. Dezember 2026; 8.3, 8.4 und 8.5 unterstützt. Abgelesen am 23. Oktober 2026. ↩︎
PHP — Unsupported branches — 8.1 End of Life 31. Dezember 2025, 8.0 26. November 2023, 7.4 28. November 2022. ↩︎
W3Techs — PHP version 8 — Anteile der Unterversionen innerhalb von PHP 8; kombiniert mit den Anteilen der Hauptversionen ergibt das 48,3 % der PHP-Sites auf nicht unterstützten Versionen. ↩︎ ↩︎
W3Techs — PHP version 7 — 7.4 macht 73,4 % der PHP-7-Sites aus. ↩︎
WordPress — Statistics — PHP-Versionen der WordPress-Sites, die an wordpress.org melden; 34,7 % unter 8.2. Abgelesen am 23. Oktober 2026. ↩︎
WordPress — Requirements — „PHP version 8.3 or greater“; läuft mit 7.4+, die „reached their official End Of Life“ haben. ↩︎
PHP manual — OPcache introduction — „OPcache improves PHP performance by storing precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request.“ Bis PHP 8.4 eine Shared Extension, geladen über
zend_extension. ↩︎ ↩︎PHP manual — OPcache runtime configuration —
opcache.jitverfügbar ab PHP 8.0.0, Standard „disable“. ↩︎Go — Frequently Asked Questions — „Go programs are compiled ahead of time to native machine code“; die Laufzeit „does not include a virtual machine“; „One of Go’s design goals is to approach the performance of C for comparable programs“. ↩︎ ↩︎
Go — package html/template — „implements data-driven templates for generating HTML output safe against code injection“; „The escaping is contextual, so actions can appear within JavaScript, CSS, and URI contexts.“ ↩︎ ↩︎
Go — Avoiding SQL injection risk — „You can avoid an SQL injection risk by providing SQL parameter values as
sqlpackage function arguments.“ ↩︎ ↩︎Go — Vulnerability management — eine kuratierte Schwachstellendatenbank; govulncheck „only surfaces vulnerabilities that actually affect you, based on which functions in your code are transitively calling vulnerable functions“. ↩︎ ↩︎
PHP manual — Backward incompatible changes in PHP 8.5 — „The Opcache extension is now always built into the PHP binary and is always loaded. The INI directives opcache.enable and opcache.enable_cli are still honored.“ ↩︎
PHP RFC — Make OPcache a non-optional part of PHP — umgesetzt in PHP 8.5; „running PHP in production without OPcache is generally considered a mistake“. ↩︎
Go — The Go Memory Model — Races auf mehrwortigen Werten „can in turn lead to arbitrary memory corruption“; ThreadSanitizer über
go build -racemeldet Races. ↩︎Go — Data Race Detector — Tests mit
go test -raceausführen; „The race detector only finds races that happen at runtime, so it can’t find races in code paths that are not executed.“ ↩︎Rust — rust-lang.org — „Rust is blazingly fast and memory-efficient: with no runtime or garbage collector“. ↩︎
Go 1.5 Release Notes — „The compiler and runtime are now implemented in Go and assembler, without C.“ ↩︎
OpenJDK — The HotSpot Group — „around 3000 C/C++ header and source files, comprising more than 1.2 million lines of code“. ↩︎
dotnet/runtime — src/coreclr — Garbage Collector (
gc/gc.cpp) und JIT (jit/compiler.cpp) sind C++. ↩︎Java SE 21 — URLClassLoader — „to load classes and resources from a search path of URLs referring to both JAR files and directories“. ↩︎
NVD — CVE-2021-44228 — „An attacker who can control log messages or log message parameters can execute arbitrary code loaded from LDAP servers“; am 10. Dezember 2021 in den CISA-KEV aufgenommen. ↩︎