21. Oktober, 14:00 UTC. Für diese Uhrzeit hatte das PHP-Security-Team ein Notfall-Release angesetzt, und zwar für zwei separate Schwachstellen mit jeweils CVSS 9.2. Früher am selben Tag hatte Laravel 12.68.0 und 13.29.0 veröffentlicht und damit eine Lücke im API-Token-Guard geschlossen, über die sich ein Angreifer auf MySQL und MariaDB als fremder Account authentifizieren konnte. Wer also eine Laravel-API auf einer MySQL-Maschine betreibt, hatte zwei Punkte auf der Liste: ein Framework-Update und ein Runtime-Update, beide kritisch, am besten erledigt, bevor der Kaffee kalt wird.

Das ist jetzt acht Tage her. Ich würde ehrlich gern sehen, wie lange es bei jedem von euch gedauert hat, bis beides in Produktion lief, denn ich vermute, die Verteilung zerfällt in zwei Gruppen, fast ohne Mittelfeld. Die eine Gruppe hat ein composer update gemergt, zugesehen, wie CI grün wird, das Image mit dem neuen PHP-Point-Release neu gebaut und Feierabend gemacht. Die andere hängt noch in einem Ticket-Thread und fragt, wem eigentlich die Staging-Umgebung gehört.

Der Unterschied zwischen diesen Gruppen ist nicht Sorgfalt. Alle haben dasselbe Advisory gelesen. Niemand, den ich kenne, hat bei einem Authentication Bypass mit den Schultern gezuckt. Was sie trennt, ist die Frage, ob das Team seiner Testsuite tatsächlich glaubt. Wenn ein grüner Lauf „alles gut“ bedeutet, ist ein kleines Framework-Update eine Sache von fünfzehn Minuten. Wenn ein grüner Lauf „wahrscheinlich gut, aber denk an das eine Mal, als die Cronjobs kaputt waren“ bedeutet, dauert dasselbe Update eine Woche, weil sich jetzt ein Mensch von Hand durch die App klicken muss, und Menschen haben viel zu tun. Genau so bleibt eine Schwachstelle noch tagelang in deinem Stack offen, obwohl der Fix längst öffentlich ist.

Das beste Gegenargument verdient eine faire Anhörung: Wer hetzt, macht Produktion kaputt, und ein Patch ohne Staging ist ein Glücksspiel für sich. Point-Releases ändern tatsächlich manchmal Verhalten. Ops-Leute, die auf eine Soak-Phase in Staging bestehen, haben Narben, die das rechtfertigen, und ich werde nicht so tun, als wäre ein Zwei-Zeilen-Diff in der composer.lock risikofrei. Aber schau dir an, wofür die Soak-Phase wirklich da ist. Sie ersetzt das Vertrauen, das du nicht in die Suite eingebaut hast. Staging findet, was deine Tests nicht abdecken. Je langsamer dein Rollout also ist, desto mehr sagt er über Lücken in der Testabdeckung aus und desto weniger über den Patch.

Deshalb ist der unscheinbarste Link aus den Nachrichten dieses Tages der nützlichste. Rob Allen hat beschrieben, wie du deine langsamsten PHPUnit-Tests findest, indem du PHPUnit mit --log-junit ein JUnit-XML-Log schreiben lässt, das dir Laufzeiten pro Test zum Sortieren liefert, und er hat darauf hingewiesen, dass PHPUnit 13 für denselben Zweck auch Open-Test-Reporting-Output erzeugen kann. Klingt nach Hausputz. Ist aber Security-Arbeit. Eine Pipeline, die vierzig Minuten braucht, läuft seltener, wird unter Druck übersprungen, und den Regressionstest, der den Patch-Tag langweilig gemacht hätte, schreibt am Ende niemand.

Im Laravel-Bug selbst steckt noch eine zweite, leisere Lektion, denn er betraf nur MySQL- und MariaDB-Setups. Wenn deine CI aus Geschwindigkeitsgründen alles gegen SQLite im Speicher laufen lässt, hattest du eine grüne Suite auf einer Datenbank, die gar nicht betroffen war, während die Produktion auf einer lief, die es war. Tempo zählt, aber es muss Tempo auf deinem echten Stack sein. Ein containerisiertes MySQL in der Pipeline kostet dich ein paar Sekunden; ein datenbankspezifischer Auth-Bypass, den du in Tests nicht reproduzieren kannst, kostet dich deutlich mehr.

Nichts davon ist ein Seitenhieb aufs Ökosystem. Die Laravel-Maintainer haben Fixes für zwei Major-Linien schnell ausgeliefert, das PHP-Team hat das Release-Fenster vorab angekündigt, damit wir planen konnten, und genau so sieht ein ausgereiftes Projekt aus. Der Engpass am 21. Oktober lag nicht upstream. Er lag in der Lücke zwischen „es gibt einen Fix“ und „meine Server laufen damit“, und diese Lücke gehört uns. Go-Entwickler prahlen gern damit, ein einzelnes statisches Binary auszuliefern; wir dürfen mit einem composer update und einem Base-Image-Bump prahlen, solange wir dem Ergebnis trauen können.

Deshalb würde mich in den Kommentaren wirklich interessieren: Wie viel Zeit ist bei deiner wichtigsten PHP-App am 21. Oktober, ehrlich gemessen, vom Advisory bis zur Produktion vergangen, und welche eine Sache in deiner Pipeline würdest du zuerst angehen, um diese Zeit zu halbieren?