October 23, 2026

Twee kritieke PHP-lekken, en waarom we Justflows in TypeScript bouwen

PHP heeft net twee bugs voor remote code execution gepubliceerd met een score van 9,2, in elke ondersteunde versie. Wat ze zijn, hoe je patcht, en waarom ze laten zien dat het ontwerp van PHP zijn beste tijd heeft gehad.

Twee kritieke PHP-lekken, en waarom we Justflows in TypeScript bouwen
Op 21 oktober 2026 publiceerde het PHP-project twee kritieke beveiligingsadviezen, CVE-2026-109618 en CVE-2026-109619. Beide scoren 9,2 op 10. Met beide kan een aanvaller zonder account en zonder wachtwoord eigen code uitvoeren op je webserver. Elke ondersteunde PHP-versie is getroffen.
Wij bouwen Justflows in TypeScript, dus deze bugs raken ons niet. Toch hebben we ze goed gelezen, omdat ze iets over PHP laten zien dat groter is dan één slechte week. Maar eerst het deel dat ertoe doet als je vandaag PHP draait.

Bug één: met opzet zonder geheugen komen

Het eerste advies (GHSA-w8hw-w9fx-j79w) heet "RCE via OOM corruption". Als een PHP-verzoek zonder geheugen komt, stopt PHP het met longjmp(), een C-instructie die direct terugspringt naar een foutafhandeling en alles daartussen overslaat. Gebeurt dat terwijl een deel van het verzoekgeheugen pas half is ingericht, dan leest de opruimcode die daarna draait geheugen dat nooit geldig was. De mislukte allocatie hoeft niet eens iets met het kapotte geheugen te maken te hebben.
Een aanvaller heeft dus alleen een manier nodig om PHP op het juiste moment zonder geheugen te laten komen. Een uploadformulier is genoeg. Het advies noemt meerdere ingangen:
  • Multipart-uploads zonder bruikbare content length kunnen data blijven sturen voorbij de controle op post_max_size.
  • Elk multipart-deel kan onbeperkt headers bevatten, die binnen PHP veel meer geheugen kosten dan over de lijn.
  • Lege bestandsvelden tellen niet mee voor max_file_uploads, maar maken wel arrays aan, en geneste veldnamen vermenigvuldigen het werk.
Het PHP-team bevestigde remote code execution via gewoon HTTP tegen mod_php, met de standaardlimieten van PHP voor geheugen en invoer. PHP-FPM en FrankenPHP lijken op basis van de broncode kwetsbaar, al is daar geen volledige exploit voor getoond. Meer workers betekent dat een aanval meer pogingen nodig heeft. Het houdt hem niet tegen.

Bug twee: het verzoek van gisteren, nog in het geheugen

Het tweede advies (GHSA-6wmf-4rv5-p3rp) heet "RCE via stale global state". PHP beschrijft zichzelf graag als shared-nothing: elk verzoek begint schoon. In de praktijk is een PHP-worker een langlopend proces dat tussen verzoeken globale state bewaart, voor fouten, sessies, objecten en extensies. De engine hoort dat allemaal na elk verzoek te resetten.
Sterft een verzoek halverwege, door een fatale fout, een time-out of geheugentekort, dan kan een deel van die state blijven wijzen naar geheugen dat al is vrijgegeven. Het volgende verzoek op dezelfde worker gebruikt het dan. Dat is een use-after-free, de klassieke bug in geheugenveiligheid, en hier leidt die tot het uitvoeren van code.
De bevestigde aanval gebruikt de voortgang van sessie-uploads, een functie die standaard aan staat. Die bleek te werken tegen zowel mod_php als PHP-FPM. Zelfs een waarschuwing over een verkeerde instelling in php.ini of een Apache-bestand .htaccess kan de stap zijn die de oude state leest. error_reporting lager zetten helpt niet.

Geen slechte week, maar een ontwerp dat zijn leeftijd laat zien

Elke taal heeft beveiligingsbugs, dus het is een terechte vraag waarom deze twee iets over PHP zelf zeggen. Kijk naar wat ze gemeen hebben:
  • Handmatig geheugenbeheer in C. Beide bugs zijn use-after-free- en niet-geïnitialiseerde-pointerfouten (CWE-416, CWE-824) in de engine. Elke PHP-extensie die in C is geschreven, voegt meer code van hetzelfde soort toe.
  • Foutafhandeling die het opruimen overslaat. longjmp() springt over alles heen wat bezig was. De fix vervangt het door een uitgestelde "zachte" out-of-memory en een directe _exit() van het hele proces. Dat is een goede fix, en hij laat zien hoe diep het probleem zat.
  • Een schone lei die moet worden nagebootst. De belofte dat elk verzoek fris begint, klopt alleen als de engine elke globale variabele reset, na elke mogelijke fout, ook na fouten midden in het opruimen van andere fouten.
  • Configuratie als aanvalsoppervlak. php.ini, .htaccess-overrides per map en de waarschuwingen die ze geven, zijn onderdeel van het aanvalspad.
Niets hiervan is een recente fout. Het is het verzoekmodel waarop PHP in de jaren negentig is gebouwd, voor een web van kleine scripts. PHP heeft sindsdien veel toegevoegd: een JIT, types, enums, readonly properties. Maar de engine eronder werkt nog steeds op dezelfde manier, en deze adviezen laten zien hoe dat er in 2026 uitziet.

Waarom Justflows in TypeScript is geschreven

Toen we met Justflows begonnen, kozen we TypeScript op Node.js voor de hele stack: server, admin, editor, plugin-SDK en thema's. Deze adviezen laten goed zien waarom.
  • Geheugen is niet de taak van het verzoek. JavaScript heeft garbage collection. Geen enkele regel Justflows-code reserveert of geeft handmatig geheugen vrij, en een fout is een exception die via try/finally afwikkelt, dus opruimcode draait altijd.
  • State is expliciet. Een Node-server is één langlopend proces, en niemand doet alsof het anders is. Daar ontwerpen we voor: verzoekdata staat in objecten die bij het verzoek horen, niet in globale variabelen van de engine die iemand moet onthouden te wissen.
  • Types van de database tot de browser. Dezelfde types beschrijven blokken, de API, de plugin-SDK en de admin-UI. Een hele categorie bugs van het type "dit was null tijdens runtime" wordt een compileerfout voordat er iets live gaat.
  • Overal één taal. De editor in je browser, de server die je pagina's rendert en de plugins die je installeert, zijn in dezelfde taal geschreven, met dezelfde tools. Er is geen splitsing tussen PHP voor de backend en JavaScript voor de frontend.

Eerlijk is eerlijk

TypeScript is geen beveiligingsgarantie, en we gaan niet doen alsof. Node.js en V8 zijn in C++ geschreven en hebben hun eigen CVE's. npm heeft supply-chain-aanvallen gehad. Je kunt in elke taal een injectiebug schrijven.
Wat verandert, is waar het risico zit. In een TypeScript-app is het geheugenonveilige deel de JavaScript-engine zelf: V8, die in miljarden browsers draait en dag en nacht wordt gefuzzd en aangevallen door een paar van de beste securityteams ter wereld. Je applicatiecode, en elke plugin, kan geen geheugen beschadigen of een losse pointer achterlaten voor het volgende verzoek. In PHP zit dat risico in een engine en een berg C-extensies die de levenscyclus van een verzoek elke keer precies goed moeten afhandelen.

Is PHP dan verouderd?

Voor het web waarvoor het is gebouwd, heeft PHP het geweldig gedaan, en een groot deel van het web draait er nog steeds op. Maar voor een nieuw project in 2026 vinden we niet dat het nog de standaardkeuze moet zijn. Een geheugenveilige taal met een echt typesysteem, één taal voor server en browser, en een runtime die niet voor elk verzoek een frisse start hoeft na te bootsen, is gewoon een beter fundament.
Draai je PHP, patch dan vandaag. Als je je volgende site plant, kijk dan eens naar de stack eronder. We zouden het leuk vinden als je naar Justflows kijkt.