Kort samengevat: PHP2Shell (CVE-2026-109618, CVE-2026-109619)
- Wat er gebeurde: op 2026-10-21 bracht PHP 8.5.12, 8.4.27, 8.3.36 en 8.2.35 uit om twee fouten met CVSS 9.2 in de engine zelf te verhelpen. Beide kunnen een aanvaller zonder account code-uitvoering geven op elke PHP-webserver, onder WordPress, Magento of Laravel.
- De aanvallen begonnen vóór de fix: de CVE-nummers lekten zo'n 23 uur voor de release uit. Cloudflare zag aanvalsverkeer vóór de patch, en watchTowr meldde 19 minuten erna misbruikpogingen.
- Gepatcht is niet schoon: een PHP-update sluit de deur maar zet niemand buiten. Bij webwinkels eindigt servertoegang vaak in een skimmer op de checkout, en die zie je alleen in de browser.
Weinig tijd? Bekijk cside's client-side scriptmonitoring. Dit helpt je de hieronder beschreven wijzigingen en gedragingen van scripts in de browser te monitoren.
Op 2026-10-21 bracht het PHP-project noodfixes uit voor twee kritieke fouten in de PHP-engine, geregistreerd als CVE-2026-109618 en CVE-2026-109619 en bijgenaamd PHP2Shell. Omdat de fouten in de runtime zitten en niet in een CMS of plugin, liep elke WordPress-, WooCommerce-, Magento-, Shopware- en Drupal-site op een ongepatchte PHP-versie tegelijk risico.
De meeste berichtgeving tot nu toe gaat over de server, en terecht: update PHP en herstart elke worker. Dit artikel gaat over het deel dat vaak wordt overgeslagen. Als een aanvaller code kan uitvoeren op een webwinkel, is de server zelden de buit. De buit is een paar regels JavaScript die aan de checkout worden toegevoegd en aan elke shopper worden geserveerd, totdat iemand kijkt wat de browser werkelijk uitvoert.
Wat er gebeurde: een oude bug en een uitgelekte bekendmaking
De onderliggende oorzaak was niet nieuw. Volgens de PHP Foundation zag een core-ontwikkelaar de eerste tekenen van het geheugentekortprobleem achter CVE-2026-109618 al tijdens de externe audit van PHP in 2024. Niemand vond toen een werkende route naar code-uitvoering, elke mogelijke fix had nadelen voor compatibiliteit of denial of service, en het werk liep vast. De Foundation noemt die vertraging een structureel falen van haar eigen proces.
Dat veranderde in augustus 2026, toen audits van Calif, OpenAI en Wiz de oude bug omzetten in werkende exploits. De gecoördineerde release stond gepland voor 2026-10-22. Dat hield geen stand.
| Wanneer (UTC) | Wat er gebeurde |
|---|---|
| 2024 | Tekenen van de geheugentekortfout gevonden tijdens de externe audit van PHP; geen exploitroute gevonden, de fix loopt vast |
| 2026-08-11 | Calif en OpenAI melden onafhankelijk van elkaar code-uitvoering op afstand met dezelfde oorzaak |
| 2026-08-24 en 2026-09-18 | Wiz en OpenAI melden extra aanvalsvectoren |
| 2026-10-20, ~15:00 | De twee CVE-nummers lekken uit op fora en sociale media, met een verkeerde releasedatum en een onjuiste CVSS-score van 10.0 |
| 2026-10-20, 19:30 | PHP kondigt de fix vooraf aan en haalt de release een dag naar voren |
| 2026-10-20, ~20:00 | Een onderzoeksbureau plaatst per ongeluk een video van een werkende proof of concept; kopieën verspreiden zich |
| 2026-10-21, 03:02 | Cloudflare zet standaard WAF-regels aan voor alle abonnementen, ook het gratis abonnement |
| 2026-10-21, 07:41 | Chainguard publiceert vroegtijdig gepatchte images, waardoor iedereen de fix kan bestuderen |
| 2026-10-21, 14:00 | PHP brengt 8.5.12, 8.4.27, 8.3.36 en 8.2.35 uit |
| 2026-10-21, 14:19 | watchTowr meldt actieve misbruikpogingen tegen beide CVE's |

Het gat dat voor verdedigers telt, zijn die ongeveer 23 uur tussen het lek en de release. Wie PHP draaide, zat dat hele venster bloot aan een bug waarvan aanvallers het bestaan al kenden, zonder patch om te installeren.
De twee kwetsbaarheden, in gewone taal
Beide bugs zitten in code die bijna elk PHP-verzoek raakt: geheugenbeheer en foutafhandeling. Beide scoren 9.2 op CVSS v4.0, en beide kunnen een niet-geauthenticeerde aanvaller code-uitvoering geven met de rechten van de webworker.
| CVE-2026-109618 | CVE-2026-109619 | |
|---|---|---|
| Korte naam | RCE via corruptie bij geheugentekort | RCE via verouderde status tussen verzoeken |
| Wat er misgaat | Een verzoek bereikt precies op het verkeerde moment de geheugenlimiet. PHP laat half geïnitialiseerde interne data achter en behandelt die bij het opruimen als geldig. | Een fatale fout laat interne status achter die wijst naar geheugen dat aan het einde van een verzoek is vrijgegeven. Het volgende verzoek op dezelfde worker gebruikt het (een use-after-free). |
| Typische trigger | Gemanipuleerde multipart/form-data-verzoeken (formulieren en bestandsuploads) die het geheugen uitputten terwijl ze binnen de limieten lijken te blijven | Een fatale fout, gevolgd door een later verzoek dat de verouderde status leest, bijvoorbeeld via session upload progress, dat standaard aanstaat |
| Ergste aangetoonde geval | RCE op Apache mod_php met één verzoek, voordat er applicatiecode draait, met standaardinstellingen | RCE op mod_php en PHP-FPM; bij FPM hangt de route af van een bewerking binnen de applicatie |
Twee details maken dit erger dan een gewone CMS-bug. Ten eerste werkt het onder je applicatie: een volledig bijgewerkte WordPress- of Magento-installatie op een kwetsbare PHP-versie is nog steeds blootgesteld, en beveiligingsplugins krijgen het verzoek nooit te zien. Ten tweede kan een aanvaller volgens de onderzoekers ook geheugen van de PHP-worker uitlezen zonder eerst code-uitvoering te krijgen. Dat geheugen kan sessietokens, wachtwoorden, API-sleutels en certificaten van andere gebruikers bevatten.
De officiële beschrijvingen zijn de advisory over corruptie bij geheugentekort en de advisory over verouderde status.
Wie getroffen is, en wordt het misbruikt?
Elke PHP-installatie die webverzoeken afhandelt valt eronder, ongeacht de server-API: PHP-FPM, Apache mod_php, php-cgi, FrankenPHP en LiteSpeed. Onderzoekers toonden niet-geauthenticeerde code-uitvoering aan op standaardinstallaties van Magento 2.4.9, WordPress, Drupal, Joomla, Nextcloud, phpMyAdmin, Laravel en andere. Sansec noemt in het bijzonder Magento-, Shopware- en WooCommerce-winkels.
| PHP-branch | Kwetsbaar | Opgelost in |
|---|---|---|
| 8.5 | onder 8.5.12 | 8.5.12 |
| 8.4 | onder 8.4.27 | 8.4.27 |
| 8.3 | onder 8.3.36 | 8.3.36 |
| 8.2 | onder 8.2.35 | 8.2.35 (branch bereikt end-of-life op 2026-12-31) |
| 8.1, 8.0, 7.4 | alle | Geen officiële release. PHP publiceerde backports van de broncode; haal een build van je leverancier of upgrade |
| 7.3 en ouder | alle | Upgrade |
Drie dingen zetten mensen op het verkeerde been. Distributiepakketten kregen de patch vooraf en kunnen die onder een oud ogend versienummer bevatten, dus zoek het CVE in de changelog van het pakket in plaats van te vertrouwen op het versienummer. De repository van Remi, populair op RHEL-gebaseerde servers, publiceerde op 2026-10-21 geen updates. En WordPress, Magento of Laravel bijwerken doet hier niets: de fix komt van je serverpakket, je hostingpartij of je container-image.
Wat misbruik betreft ging het snel. Cloudflare zegt dat het aanvalsverkeer op zijn klanten zag voordat de patch uitkwam, en zag hoe aanvallers payloads aanpasten om zijn regels te omzeilen. watchTowr meldde om 14:19 UTC actieve misbruikpogingen tegen beide CVE's. Op het moment van publicatie heeft geen enkele bron publiekelijk een geslaagde compromittering van een specifieke server bevestigd. Verschillende organisaties, waaronder Nederlandse overheidsdiensten en BambooHR, gingen uit voorzorg offline in plaats van af te wachten.
Kon je niet binnen dat venster patchen, ga er dan van uit dat je bent afgetast.
Waarom een serverbug een checkoutprobleem wordt
Bij een webwinkel is een shell een middel, geen doel. Dit gebeurde na elke golf van massaal misbruik tegen PHP-e-commerceplatformen, met CosmicSting in 2024 als bekendste voorbeeld: aanvallers krijgen code-uitvoering, plaatsen een achterdeur en veranderen daarna wat de winkel naar de browsers van shoppers stuurt. Het geld zit in de kaartnummers die in de checkout worden ingetypt, en die bestaan alleen in de browser.
De keten ziet er meestal zo uit:
- Exploit. Een gemanipuleerd verzoek bereikt een ongepatchte PHP-worker.
- Code-uitvoering. De code van de aanvaller draait als de webgebruiker, zonder in te loggen.
- Persistentie. De aanvaller plaatst een webshell, een cronjob of een nieuw beheerdersaccount. Dat overleeft je PHP-update, want patchen sluit de deur maar zet niemand buiten die al binnen is.
- Injectie. De aanvaller verandert wat de browser ontvangt: een
<script>-tag in een checkouttemplate, een aangepaste eigen JavaScript-bundle of, heel vaak bij Magento en WordPress, een fragment in de database (headerinstellingen van het thema, CMS-blokken, widgetopties) waar controles op bestandsintegriteit nooit kijken. - Verzameling. De browser van elke shopper voert de skimmer uit. Die leest de kaartvelden, of toont een nep-betaalformulier, en stuurt de gegevens naar een domein dat eruitziet als een analytics- of CDN-host.
De webwinkel komt er meestal achter via een common point of purchase-melding van een kaartmaatschappij, weken of maanden nadat de eerste kaart is gestolen.
Elke verdediging dekt een ander deel van die keten:
| Verdediging | Dekt | Mist |
|---|---|---|
| PHP-update | Stap 1, voor elk verzoek na de installatie | Alles wat vóór het patchen is geplaatst |
| WAF | Stap 1, het binnenkomende exploitverzoek | Aangepaste payloads; alles na het verzoek |
| Serverforensisch onderzoek en bestandsintegriteit | Stap 2 tot en met 4, in bestanden en logs | Scripts in de database; wat de pagina in de browser doet |
| Scriptmonitoring in de browser | Stap 4 en 5, wat checkoutpagina's werkelijk uitvoeren en waar ze data naartoe sturen | De servercompromittering zelf |

Moderne skimmers zijn gebouwd om onzichtbaar te blijven voor tools die de serverkant controleren. Ze worden alleen actief op de checkoutroute, maar één keer per sessie, alleen voor bepaalde landen of alleen als er geen developer tools openstaan, zodat een crawler vanuit een datacenter een schone pagina krijgt. Die truc van één keer per sessie zagen we een paar dagen geleden nog bij de HulkApps-checkoutkaping. Een WAF ziet de binnenkomende exploit, niet het script dat je pagina drie weken later serveert. De enige plek waar de skimmer zich betrouwbaar laat zien, is de browsersessie van een echte klant.
Gepatcht is niet hetzelfde als schoon: wat je nu moet controleren
Als je PHP-servers op enig moment na het lek van 2026-10-20 met een getroffen versie aan internet hingen, loop dan beide lijsten hieronder door. De eerste gaat over de server. De tweede gaat over wat de browsers van je klanten ontvangen, en dat is de lijst die de meeste incidentchecklists vergeten.

Op de server
- Bewaar eerst het bewijs. Maak een kopie van PHP- en webserverlogs, configuratie en verdachte bestanden voordat je iets verandert.
- Update en herstart. Installeer de verbeterde PHP-build en herstart daarna Apache, PHP-FPM en elke langlopende worker. Een bijgewerkt pakket met oude workers die nog draaien, is nog steeds kwetsbaar.
- Zoek naar persistentie. Kijk naar nieuwe of gewijzigde PHP-bestanden in webroots en uploadmappen, onverwachte cronjobs en beheerders die niemand heeft aangemaakt.
- Zoek in de logs naar de vingerafdrukken van de exploit. De onderzoekers raden aan te letten op ongebruikelijke multipart-verzoeken gevolgd door geheugenlimietfouten of reeksen HTTP 500-fouten, opvallend grote
PHPSESSID-cookies in responses en onverklaarbare herstarts van PHP-workers. - Let op procesgedrag. Uitgaande verbindingen vanaf PHP-workers, of
sh,curlofwgetgestart doorphp-fpm, zijn sterke signalen. - Roteer wat in het geheugen stond. Omdat het geheugen van workers zonder code-uitvoering kon worden uitgelezen, roteer je API-sleutels, databasegegevens en geheimen van je betaalgateway die PHP-processen in handen hadden, en overweeg je actieve sessies ongeldig te maken.
In de browser
- Inventariseer elk script op je gevoelige pagina's. Eerst checkout, betaling, inloggen en account. Neem ook je eigen bundles mee, niet alleen tags van derden.
- Vergelijk met een baseline van vóór 2026-10-20. Elk nieuw script, elke gewijzigde bestandshash en elk nieuw domein waarmee de checkout praat, verdient een verklaring.
- Controleer de plekken waar skimmers zich buiten je code verstoppen. In Magento de HTML-head-instelling "Scripts and Style Sheets" en de footerinstelling "Miscellaneous HTML", CMS-blokken en widgets. In WordPress plugins voor header- en footerinjectie, widgets en thema-opties in de database.
- Vertrouw niet op één crawl. Een skimmer die één keer per sessie afgaat of IP-adressen van datacenters overslaat, komt door een scan heen. Je hebt waarnemingen uit echte sessies nodig, over langere tijd.
- Let op uitgaande verzoeken vanaf de checkout. Kaartgegevens moeten de pagina op de een of andere manier verlaten: een
fetch, een image beacon, een WebSocket. Een nieuwe bestemming op de betaalpagina is het duidelijkste signaal dat je zult krijgen. - Bekijk CSP-overtredingsrapporten, als je die verzamelt. Een rapport met een domein dat je nooit hebt gebruikt, is het uitzoeken waard, ook als de pagina er normaal uitziet.
Niets hiervan vervangt de patch. Het beantwoordt de vraag die de patch niet kan beantwoorden: is er iets veranderd terwijl de deur openstond?
Wat dit betekent voor PCI DSS 6.4.3 en 11.6.1
PHP2Shell is een schoolvoorbeeld voor de twee eisen uit PCI DSS 4.0.1 die op 2025-03-31 verplicht werden.
- Eis 6.4.3 vraagt je om elk script te beheren dat op een betaalpagina in de browser van de consument wordt geladen en uitgevoerd: bevestig dat elk script geautoriseerd is, borg de integriteit ervan en houd een inventaris bij met een schriftelijke rechtvaardiging per script. Een skimmer die na een servercompromittering is geïnjecteerd, is per definitie een niet-geautoriseerd script.
- Eis 11.6.1 vraagt om een mechanisme voor het detecteren van wijzigingen en manipulatie dat je waarschuwt bij ongeautoriseerde wijzigingen in scripts op betaalpagina's en in beveiligingsrelevante HTTP-headers, zoals de browser ze ontvangt. Dat is precies de wijziging die een aanvaller doet in stap 4 van de keten hierboven.
Twee praktische vragen voor je volgende assessment. Hoe vaak beoordeelt je 11.6.1-mechanisme de pagina werkelijk? Als het antwoord wekelijks is, kan een skimmer die op 2026-10-21 is geïnjecteerd dagen draaien voordat iemand het merkt. En dekt je bewijs de periode vanaf 2026-10-20? Als je kunt aantonen dat de scriptinventaris van je betaalpagina's niet is veranderd, heb je een helder antwoord. Zo niet, dan is het de moeite waard om dat gat nu te dichten.
Ook webwinkels met SAQ A die het iframe van een betaalprovider insluiten, zijn niet vrijgesteld. Sinds de herziening van SAQ A in januari 2025 hangt de geschiktheid af van de bevestiging dat je site niet kwetsbaar is voor scriptaanvallen die je e-commercesystemen kunnen raken. Een gecompromitteerde bovenliggende pagina kan dat iframe nog steeds vervangen of overlappen.
Waar cside past
Om de reikwijdte duidelijk te maken: cside patcht PHP niet en houdt het exploitverzoek niet tegen. Dat is de taak van je PHP-update en je WAF. cside dekt de laag die daarna komt: wat je pagina's werkelijk uitvoeren in de browsers van je klanten.
Echte sessies, geen synthetische crawls. cside monitort scripts in echte sessies van shoppers in plaats van te vertrouwen op een periodieke scan, zodat een skimmer die één keer per sessie afgaat of zich verbergt voor datacenters toch onder onze ogen draait.
Wijzigingen en gedrag, niet alleen bestandsnamen. Een nieuw script op de checkout, een aangepaste eigen bundle of een script dat kaartvelden begint uit te lezen en naar een domein stuurt dat je winkel nooit heeft gebruikt, levert een melding op, met de inhoud van het script beschikbaar voor inspectie.
Gestopt in de sessie. Met Script Method haalt cside elk script van derden aan serverzijde op om het te hashen, te archiveren en te analyseren, en blokkades worden tijdens runtime in de browser afgedwongen, naast CSP. Een niet-geautoriseerd script, of een specifieke functie die het probeert te gebruiken, wordt in de sessie gestopt in plaats van achteraf gemeld.
Bewijs voor PCI. PCI Shield houdt de scriptinventaris voor 6.4.3 en de wijzigingsmeldingen voor 11.6.1 bij, met wekelijkse rapporten die je assessor kan lezen.
De details hierboven geven openbare berichtgeving en verklaringen van leveranciers weer per 2026-10-21. We werken dit artikel bij zodra meldingen over misbruik veranderen.
Als cside je checkout op 2026-10-20 al monitorde, bekijk dan de gegevens die sindsdien zijn vastgelegd of boek een demo om ze met ons team door te nemen. Begin gratis om vanaf de implementatie te monitoren. Nieuwe implementaties kunnen eerdere browsersessies niet reconstrueren.
Bronnen
- PHP-securityadvisory: RCE via corruptie bij geheugentekort (GHSA-w8hw-w9fx-j79w)
- PHP-securityadvisory: RCE via verouderde status (GHSA-6wmf-4rv5-p3rp)
- PHP-aankondiging, 2026-10-21
- The PHP Foundation: Today's PHP security release, and how we're strengthening PHP security
- Cloudflare: Cloudflare deploys protections against php2shell vulnerability
- watchTowr: PHP Remote Code Execution (PHP2Shell)
- Rapid7: CVE-2026-109618 and CVE-2026-109619
- The Hacker News: PHP issues emergency patches for two critical PHP2Shell RCE flaws
- Sansec: PHP2Shell critical PHP RCE
- CERT-EU Security Advisory 2026-018








