Auf der diesjährigen International PHP Conference in München hat mich Ines Chargui interviewt. Die Fragen habe ich vorab bekommen: Der erste Teil drehte sich um Security, vom neuen Verhalten von Composer bis zu PHP2Shell, der zweite Teil blickte auf das Jahr zurück und auf das nächste voraus. Zusätzlich zum Video wollte ich eine schriftliche Fassung des Interviews, in der ich meine Antworten klarer formulieren kann, als es vor einer Kamera möglich ist.
Die Fragen gebe ich so wieder, wie sie gestellt wurden. Wo sie von KI sprechen, ist in meinen Antworten von LLM-basierten Werkzeugen die Rede: Mit dem genaueren Begriff lässt sich leichter besprechen, was diese Werkzeuge tun und was sie nicht tun.
Von der Warnung zur Blockade
Frage: Composer warnt Entwicklerinnen und Entwickler nicht mehr nur vor gefährlichen Abhängigkeiten, es verhindert aktiv deren Installation. Wie schnell wird aus einer Sicherheitslücke, die heute entdeckt wird, eine Blockade in Composer, und wo entstehen die größten Verzögerungen?
Der Teil, für den Composer verantwortlich ist, ist schnell. Packagist sammelt Security Advisories aus der GitHub Advisory Database und der Datenbank FriendsOfPHP Security Advisories, und seit Composer 2.9 weigert sich composer update, eine Version zu installieren, die von einem bekannten Advisory betroffen ist. Sobald ein Advisory veröffentlicht ist, dauert es Minuten und nicht Tage, bis es blockiert.
Die Verzögerungen liegen davor und danach. Davor muss eine Sicherheitslücke behoben und ein Advisory eingereicht werden, und zwar mit korrekten Versionsbereichen: Zu weit gefasste Bereiche blockieren Versionen, die in Ordnung sind, zu eng gefasste lassen betroffene Versionen durch. Diese Arbeit leisten Maintainerinnen und Maintainer, von denen viele ehrenamtlich arbeiten. Danach greift die Blockade nur, wenn Abhängigkeiten aufgelöst werden, also bei composer update, composer require und composer remove, nicht aber bei composer install aus einer bestehenden Lock-Datei. Versionen, die als Malware markiert sind, bilden die Ausnahme: Seit Composer 2.10 werden sie auch bei composer install blockiert. Ein Projekt, das aus seiner Lock-Datei deployt und seine Abhängigkeiten selten aktualisiert, wird deshalb nie durch ein Advisory blockiert. Darum empfehle ich dir, composer audit in deiner CI-Pipeline regelmäßig zeitgesteuert auszuführen und nicht nur dann, wenn sich deine Abhängigkeiten ändern: Neue Advisories werden auch für Versionen veröffentlicht, die du vor Monaten installiert hast.
Nichts geändert, und trotzdem schlägt alles fehl
Frage: Was wird für Entwicklerinnen und Entwickler die größte Überraschung sein, wenn sie auf das neue Verhalten von Composer umsteigen?
Dass composer update fehlschlägt, obwohl sie nichts geändert haben. Ein Paket, an das sie seit Jahren nicht gedacht haben, oft eine Abhängigkeit einer Abhängigkeit, hat eine bekannte Sicherheitslücke. Wo Composer früher eine Warnung ausgab, die leicht zu übersehen war, weigert es sich jetzt, die Abhängigkeiten aufzulösen. Bei Projekten, die über die Jahre Update-Schulden angehäuft haben, werden diese Schulden plötzlich sichtbar.
Die naheliegende Reaktion ist, die Blockade abzuschalten. Bitte tu das nicht. Die Sicherheitslücke war schon vorher da; geändert hat sich nur, dass du jetzt von ihr weißt. Wenn du wirklich gerade nicht aktualisieren kannst, erlaubt dir Composer, ein bestimmtes Advisory zu ignorieren und den Grund dafür in deiner composer.json festzuhalten. Das ist eine dokumentierte Entscheidung, die sich später überprüfen lässt, statt eines abgeschalteten Mechanismus, den alle vergessen.
Auch die Laufzeitumgebung ist eine Abhängigkeit
Frage: Bei dem PHP-Vorfall war die Laufzeitumgebung selbst betroffen, während Supply Chain-Angriffe auf Pakete zielen können. Wie sollten Entwicklerinnen und Entwickler eine Sicherheitsstrategie aufbauen, die beides abdeckt?
PHP2Shell hat gezeigt, dass composer.lock nur einen Teil dessen beschreibt, was wir ausführen. Die beiden Sicherheitslücken, CVE-2026-109618 und CVE-2026-109619, stecken in PHP selbst. Mit mod_php kann eine nicht authentifizierte Anfrage den Exploit auslösen, bevor auch nur eine Zeile Code der Anwendung läuft. Nichts in deiner Anwendung, in ihren Abhängigkeiten oder in deiner Composer-Konfiguration hätte dich davor schützen können.
Meine Antwort ist, die Laufzeitumgebung wie jede andere Abhängigkeit zu behandeln. Du musst wissen, welche PHP-Version wo läuft: auf Servern, in Container-Images, in der CI und in Appliances oder Produkten von Herstellern, die PHP mitbringen und die du nicht selbst aktualisieren kannst. Und du musst ein Patch-Release von PHP so routiniert ausrollen können wie das Update eines Composer-Pakets: über dieselbe Pipeline, geprüft durch dieselben Tests, mit derselben Zuversicht. Ein Inventar, das deine Composer-Pakete auflistet, aber nicht deine PHP-Laufzeitumgebung, ihre Extensions und die Systembibliotheken, gegen die sie gelinkt ist, ist unvollständig.
Updates langweilig machen
Frage: Wie können Entwicklungsteams lernen, Sicherheitsvorfälle vorherzusehen, statt nur auf sie zu reagieren?
Teams, die von Sicherheitsvorfällen überrascht werden, fehlt selten die Information. Ihnen fehlt eine Routine. Wenn das Update von PHP oder einer Abhängigkeit ein Projekt ist, das geplant und geschätzt werden muss und dann verschoben wird, wird jeder Security-Fix zum Notfall. Wenn Updates klein, häufig und langweilig sind, ist ein Notfall nur ein normales Update, das zufällig dringend ist.
Dafür brauchst du eine Testsuite, der du vertraust, statische Analyse und automatisiertes Deployment. Du musst wissen, was du betreibst. Du musst bewusst mit Abhängigkeiten umgehen: Jede Abhängigkeit ist eine Entscheidung, die du immer wieder neu treffen musst, also bedeuten weniger Abhängigkeiten weniger Entscheidungen. Und du musst unterstützte PHP-Versionen verwenden. Für PHP2Shell hat das Security-Team von PHP eine Ausnahme gemacht und minimale Backports im Quelltext für PHP 7.4, PHP 8.0 und PHP 8.1 veröffentlicht. Auf solche Ausnahmen solltest du nicht bauen.
Die ersten Stunden nach der Offenlegung
Frage: Wenn eine kritische Sicherheitslücke offengelegt wird, worum sollten sich Entwicklerinnen und Entwickler zuerst kümmern, und welche Fehler sollten sie vermeiden?
Finde zuerst heraus, ob und wo du betroffen bist: welche Systeme die betroffene Software betreiben, in welchen Versionen, und welche davon aus dem Internet erreichbar sind. Ohne Inventar dauert dieser Schritt am längsten, und deshalb muss das Inventar existieren, bevor eine Sicherheitslücke offengelegt wird. Dann patchst du, angefangen bei den exponierten Systemen, idealerweise über deine normale Deployment-Pipeline.
Drei Fehler solltest du vermeiden. Der erste ist, eine Gegenmaßnahme wie eine WAF-Regel für die Behebung zu halten. Für PHP2Shell haben Core-Entwicklerinnen und -Entwickler von PHP klar gesagt, dass keine Gegenmaßnahme Angriffe vollständig abwehrt und dass die offiziellen Patches der einzige dauerhafte Schutz sind. Der zweite ist die Annahme, dass ein gepatchtes System ein sauberes System ist. Ein Patch schließt die Lücke, aber er beseitigt keine Kompromittierung, die vorher stattgefunden hat, und saubere Logs beweisen nicht, dass nichts passiert ist. Der dritte ist, die Dringlichkeit als Grund zu nehmen, Tests zu überspringen oder das Security-Update unter Zeitdruck mit einem größeren Upgrade zu verbinden.
Automatisierung und ihre Grenzen
Frage: Können wir Sicherheitsentscheidungen automatisieren, ohne ein falsches Gefühl von Sicherheit zu erzeugen?
Ja, und das sollten wir auch. Dass Composer Versionen mit bekannten Sicherheitslücken und bekannte Malware standardmäßig blockiert, ist ein gutes Beispiel: Eine Entscheidung, die viele falsch getroffen haben, indem sie sie gar nicht getroffen haben, fällt jetzt standardmäßig richtig aus.
Ein falsches Gefühl von Sicherheit entsteht nicht durch die Automatisierung selbst, sondern dadurch, dass missverstanden wird, was sie tut. Automatisierung kann nur auf das reagieren, was bereits bekannt ist. Ein erfolgreiches composer audit bedeutet, dass es für die Versionen, die du installiert hast, keine bekannten Advisories gibt. Es bedeutet nicht, dass deine Abhängigkeiten sicher sind, genauso wenig wie 100 % Code Coverage bedeutet, dass deine Tests irgendetwas prüfen. Das zweite Risiko ist das Abschalten: Wenn die Automatisierung zum ersten Mal im Weg ist, schaltet jemand sie global ab, und niemand schaltet sie je wieder ein. Jede Ausnahme sollte explizit sein, auf ein bestimmtes Advisory beschränkt, begründet und regelmäßig überprüft.
Schneller finden, langsamer beheben
Frage: Wird KI Entwicklerinnen und Entwicklern helfen, Sicherheitslücken schneller zu finden und zu beheben, oder verschafft sie der Angriffsseite einen noch größeren Vorteil?
Beides. LLM-basierte Werkzeuge senken die Kosten für das Finden von Sicherheitslücken, und zwar auf beiden Seiten, bei der Verteidigung wie beim Angriff. Gleichzeitig wird das Zeitfenster zwischen Offenlegung und Ausnutzung immer kürzer: Im Fall von PHP2Shell wurden Angriffe beobachtet, noch bevor die korrigierten Releases verfügbar waren.
Ob die Verteidigung die Nase vorn hat, hängt davon ab, wie schnell Sicherheitslücken behoben und wie schnell diese Korrekturen ausgerollt werden, und nicht davon, wie schnell sie gefunden werden. Der Engpass sind Menschen: Maintainerinnen und Maintainer, die Meldungen sichten, Fixes schreiben und Releases koordinieren. Viele von ihnen arbeiten ehrenamtlich und kämpfen schon jetzt mit einer Flut minderwertiger, maschinell erzeugter Meldungen über Sicherheitslücken. Wenn uns diese Werkzeuge helfen, mehr Sicherheitslücken zu finden, müssen wir die Menschen finanzieren, die sie beheben. Deshalb ist es Security-Arbeit, Maintainerinnen und Maintainer zu unterstützen, so wie es die PHP Foundation, in deren Board ich Mitglied bin, für PHP selbst tut.
Security by Default
Frage: Welche Neuigkeit aus dem PHP-Universum oder aus der Softwareentwicklung war für dich in diesem Jahr die spannendste?
Die Arbeit des Teams hinter Composer und Packagist. Das Blockieren anhand von Advisories ist seit Composer 2.9 der Standard. Composer 2.10 hat einen Malware-Filter hinzugefügt, der für alle, die Packagist.org verwenden, standardmäßig aktiviert ist, und dazu eine einheitliche Konfiguration für Policies. Packagist hat stabile Versionen unveränderlich gemacht, sodass ein neu getaggtes Release ein bereits veröffentlichtes nicht mehr unbemerkt ersetzen kann. Und Composer 2.11 bringt eine Cooldown-Policy. Zusammengenommen wird Supply Chain Security im PHP-Ökosystem damit von etwas, für das du dich aktiv entscheiden musst, zu etwas, das du standardmäßig bekommst.
Am bemerkenswertesten finde ich, dass hier kein großer Security-Anbieter am Werk ist, sondern ein kleines Team, das Infrastruktur pflegt, von der das gesamte PHP-Ökosystem abhängt. Über den Druck, unter dem diese Infrastruktur steht, habe ich in Composer und Packagist im Supply Chain-Stresstest geschrieben. Dieses Team tut mehr für die Sicherheit unseres Ökosystems, als den meisten bewusst ist, die es nutzen.
Die Verantwortung wandert nicht zum Werkzeug
Frage: Wenn KI-Agenten neben Entwicklerinnen und Entwicklern zu echten Beteiligten an der Softwareentwicklung werden, wie sollten wir dann Zuständigkeit und Verantwortung neu denken, wenn KI-generierter Code Fehler, Sicherheitslücken oder unerwartetes Verhalten einführt?
Ich würde die Prämisse infrage stellen. Ein Agent kann ein nützliches Werkzeug sein, aber er kann nicht zur Verantwortung gezogen werden, und deshalb ist er kein Beteiligter im Sinne der Frage. Wer den Code merged, verantwortet ihn, genau wie bei Code, den jemand aus dem Team, ein externer Dienstleister oder die Maintainerinnen und Maintainer einer Open Source-Abhängigkeit geschrieben haben. „Der Agent hat das geschrieben“ ist keine bessere Ausrede als „Ich habe das von Stack Overflow kopiert“.
Was sich ändert, ist der Ort, an dem Verantwortung wahrgenommen wird. Wenn du nur noch reviewst, was ein Agent produziert hat, verlierst du nach und nach das Verständnis, das du brauchst, um die Verantwortung dafür zu übernehmen. Reviewen ist nicht dasselbe wie Spezifizieren. Deshalb halte ich den fehlschlagenden Test, von einem Menschen geschrieben und als Ausdruck dessen, was der Code tun soll, für den Teil der Arbeit, der nicht delegiert werden darf. Wer Code verantwortet, verantwortet seine Spezifikation.
Schneller, als wir verstehen können
Frage: Wo siehst du das größte Spannungsfeld zwischen dem Tempo, das KI der Softwareentwicklung verspricht, und der Notwendigkeit, immer komplexere Anwendungen verständlich, wartbar und beherrschbar zu halten?
Code lässt sich heute schneller produzieren, als er sich verstehen lässt. Jede Zeile Code, die niemand im Team versteht, ist eine Form von Schulden. Margaret-Anne Storey beschreibt das in „From Technical Debt to Cognitive and Intent Debt“ als Verschiebung von Schulden im Code hin zu Schulden in unseren Köpfen. Diese Schulden werden im ungünstigsten Moment fällig: während eines Vorfalls, unter Zeitdruck oder wenn ein Upgrade sofort passieren muss, weil die Laufzeitumgebung eine kritische Sicherheitslücke hat.
Lesbarer Code und grüne Tests reichen nicht. Als ich einen Agenten eine neue Metrik für eine meiner eigenen Bibliotheken, sebastian/complexity, implementieren ließ, war der Code lesbar und die Tests waren grün, und trotzdem konnte ich nicht beurteilen, ob das Ergebnis korrekt war. Kontrolle entsteht daraus, dass du weißt, was der Code tun soll, und prüfen kannst, ob er es tut. Code, der richtig aussieht, reicht dafür nicht.
Plausibel ist nicht korrekt
Frage: Was verstehen Entwicklerinnen und Entwickler deiner Meinung nach derzeit an KI am meisten falsch, und was werden sie in den nächsten Jahren über Softwareentwicklung verlernen müssen?
Sie halten Plausibles für korrekt. LLM-basierte Werkzeuge produzieren Code, der richtig aussieht, und Tests, die zusammen mit diesem Code generiert werden, bestätigen, was der Code tut, und nicht, was er tun soll. Eine Testsuite, die aus einer Implementierung abgeleitet wurde, kann die Fehler in dieser Implementierung nicht finden.
Verlernen müssen wir die Vorstellung, dass das Schreiben von Code der Engpass der Softwareentwicklung ist. Das war es eigentlich nie, und jetzt ist es das ganz sicher nicht mehr. Knapp sind andere Fähigkeiten: das Problem verstehen, die Lösung spezifizieren, das Ergebnis prüfen und entscheiden, was nicht gebaut wird. Wir werden auch verlernen müssen, Fortschritt an produziertem Code zu messen: Code ist eine Verbindlichkeit, und mehr davon schneller zu produzieren, ist für sich genommen kein Fortschritt.
Wegwerfsoftware
Frage: Welche Entwicklung in der Softwareentwicklung hat dich in diesem Jahr enttäuscht?
Die Welle von Rewrites etablierter Werkzeuge, die von Agenten generiert wurden: Composer in Rust, wieder ein neues Testing-Framework, an einem Wochenende gebaut. Sie ziehen Aufmerksamkeit auf sich, aber niemand hat sich verpflichtet, sie die nächsten zehn Jahre zu pflegen, ihre Sicherheitsmeldungen zu bearbeiten oder sie abwärtskompatibel zu halten. Das ist Wegwerfsoftware. Für Experimente ist das in Ordnung, aber du solltest nicht darauf aufbauen.
Was Werkzeuge wie Composer oder PHPUnit wertvoll macht, ist nicht ihr Code. Es sind Jahre, manchmal Jahrzehnte der Wartung, der Entscheidungen darüber, was sie nicht tun, und einer Verlässlichkeit, auf die andere aufbauen können. Das lässt sich nicht an einem Wochenende generieren.
Finde heraus, was deine Tests wert sind
Frage: Hast du einen Geheimtipp für unser Publikum: ein Werkzeug, eine Technologie oder einen Produktivitäts-Booster, den alle ausprobieren sollten?
Mutation Testing mit Infection. Infection nimmt kleine Änderungen an deinem Code vor, ersetzt zum Beispiel < durch <= oder entfernt einen Methodenaufruf, und prüft dann, ob deine Tests das bemerken. Jede Änderung, die unbemerkt bleibt, zeigt dir Code, den deine Tests ausführen, aber nicht prüfen.
Führe es einmal aus, zunächst auf einem kleinen Teil deiner Codebasis. Das ist eine ernüchternde Erfahrung, besonders bei Code mit hoher Code Coverage, denn Code Coverage sagt dir nur, welcher Code ausgeführt wurde, und nicht, welcher Code geprüft wurde. Besonders aufschlussreich ist es bei Code und Tests, die von einem Agenten generiert wurden.
Die richtigen Tests ausführen
Frage: Dein Vorsatz für 2027: Auf welches Thema möchtest du dich im neuen Jahr konzentrieren?
Darauf, wie PHPUnit Tests ausführt. Ich möchte, dass PHPUnit die richtigen Tests ausführt, parallel und nur so oft wie nötig: nur die Tests, die von einer Änderung betroffen sind, unabhängige Tests gleichzeitig und Tests dort wiederholt, wo es nötig ist, um diejenigen aufzudecken, die nur zufällig bestehen.
Der Grund ist einfach: Wenn Code schneller produziert wird, muss auch das Feedback schneller sein, und es muss vertrauenswürdig sein. Eine Testsuite, die dreißig Minuten braucht, wird nicht oft genug ausgeführt, und einer Testsuite mit Flaky Tests glaubt niemand. Beides untergräbt genau das, was wir gerade am dringendsten brauchen: die Fähigkeit zu prüfen.
Policy as Code für Abhängigkeiten
Frage: Welchen Trend siehst du derzeit, der im kommenden Jahr an Fahrt gewinnen wird?
Policies für Abhängigkeiten, die der Paketmanager selbst durchsetzt. Die neue Policy-Konfiguration von Composer führt Advisories, Malware und aufgegebene Pakete zusammen, unterstützt eigene Policies aus externen Quellen und bekommt mit Composer 2.11 einen Cooldown, der Versionen ablehnt, die gerade erst veröffentlicht wurden. Organisationen werden eigene Regeln definieren und sie auf jedem Entwicklungsrechner und in jeder CI-Pipeline durchsetzen lassen.
Der Cyber Resilience Act wird dem zusätzlichen Schwung geben, weil es für viele Organisationen von guter Praxis zur Pflicht wird, die eigenen Abhängigkeiten zu kennen. Solche Policies brauchen allerdings Sorgfalt: Ein Cooldown, der ein bösartiges Release fernhält, verzögert auch einen Security-Fix. Policies brauchen gut durchdachte Ausnahmen, sonst werden sie abgeschaltet.
Ungeprüft
Frage: Wie würdest du den Zustand der Softwareentwicklung mit nur einem Wort beschreiben?
Ungeprüft. Wir produzieren mehr Code als je zuvor und prüfen weniger davon: Code, der von Werkzeugen generiert wurde, Abhängigkeiten, die sich niemand angesehen hat, und Laufzeitumgebungen, von denen wir nicht wussten, dass wir sie betreiben.
Die gute Nachricht ist, dass die Werkzeuge zum Prüfen nie besser waren: Tests, statische Analyse, Mutation Testing, Audits der Abhängigkeiten und Software Bills of Materials. Wir müssen sie nur nutzen.
Zum Schluss möchte ich Ines Chargui für das Interview und für ihre durchdachten Fragen danken.