PHP2Shell: come capire se il tuo PHP ha davvero la patch
PHP2Shell tocca quasi ogni sito in PHP, WordPress compreso. Come leggere la versione vera sul server, perché il numero inganna e cosa fare con PHP 7.

Indice dei contenuti
Il 21 ottobre il progetto PHP ha pubblicato due correzioni per falle che permettono a chiunque di eseguire codice su una macchina altrui, senza login. I ricercatori che le hanno scoperte le hanno raccolte sotto il nome PHP2Shell e toccano quasi ogni sito scritto in PHP, quindi anche ogni WordPress. La risposta ufficiale è una sola, “aggiorna”, ma prima bisogna sapere quale interprete gira davvero sul server: ed è proprio quel numerino la cosa più facile da fraintendere.
In questo articolo trovi come controllare la versione da WordPress e da terminale, perché un’installazione corretta può dichiarare una versione “vecchia”, cosa puoi fare se non riesci ad aggiornare subito e cosa succede ai siti fermi a PHP 7. Ho provato tutti i comandi su Ubuntu 24.04 con PHP 8.3.
Cosa è successo il 21 ottobre
L’avviso di sicurezza di php.net dice che PHP 8.5.12, 8.4.27, 8.3.36 e 8.2.35 correggono due vulnerabilità critiche di tipo RCE (remote code execution, cioè la possibilità di far girare comandi propri sul server di qualcun altro):
- CVE-2026-109618: quando PHP esaurisce la memoria può interrompersi a metà, con dati interni della richiesta inizializzati solo in parte. La pulizia di fine richiesta li tratta poi come validi.
- CVE-2026-109619: uno stato interno sopravvive alla liberazione della memoria che lo conteneva, e una richiesta successiva servita dallo stesso processo può riusarlo.
Secondo l’avviso sono a rischio tutte le installazioni PHP che rispondono a richieste web, tra cui PHP-FPM, Apache con mod_php, php-cgi, FrankenPHP e LiteSpeed. Il rischio più alto è su mod_php, dove è stato dimostrato un attacco che parte prima che il codice dell’applicazione venga eseguito.
Il Post ha raccontato che le falle sono state trovate da ricercatori di Calif e Wiz con l’aiuto dell’intelligenza artificiale, e che numerose istituzioni e aziende hanno messo offline i propri siti per timore di attacchi. Tra le pagine non disponibili il giornale citava alcune voci di Wikipedia, il sito del governo finlandese e quello dell’agenzia per la cybersicurezza olandese.
Quale versione di PHP usa il tuo sito
Su WordPress la strada più veloce è il pannello: la documentazione ufficiale indica Strumenti > Salute del sito > Info, dove nella sezione Server trovi, tra le variabili PHP, anche la versione. È il dato del processo che serve le pagine, non del terminale, e la differenza pesa: su parecchie macchine convivono più installazioni.
Con un accesso SSH, la verifica minima è questa:
php -v
php -r 'echo PHP_VERSION, PHP_EOL;'
Attenzione però: php da terminale è l’eseguibile CLI (command line interface), che può differire da quello usato da PHP-FPM o da Apache. Su un VPS con diverse installazioni affiancate, il pannello di WordPress resta il riferimento.
C’è anche chi controlla dall’esterno con l’header X-Powered-By, che PHP aggiunge alle risposte delle pagine .php quando expose_php è attivo. Sul mio ambiente di prova, con il server di sviluppo integrato e un index.php di una riga:
echo '<?php echo "ok";' > index.php
php -S 127.0.0.1:8099 >/dev/null 2>&1 &
sleep 1
curl -sI http://127.0.0.1:8099/ | grep -i x-powered-by
# X-Powered-By: PHP/8.3.6
kill %1
Parecchi scanner online si limitano a questo. E qui nasce l’equivoco.
Perché il numero di versione inganna
Secondo la tabella dell’avviso, sul ramo 8.3 la prima release corretta è la 8.3.36. Il mio PHP dice 8.3.6: trenta release indietro. Un piccolo script lo segnala subito:
<?php
// Prima release di ogni ramo con la patch per CVE-2026-109618 e CVE-2026-109619
$fixed = ['8.2' => '8.2.35', '8.3' => '8.3.36', '8.4' => '8.4.27', '8.5' => '8.5.12'];
$branch = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION;
if (!isset($fixed[$branch])) {
echo "PHP {$branch}: nessuna release php.net con la patch, controlla il pacchetto\n";
} elseif (version_compare(PHP_VERSION, $fixed[$branch], '<')) {
echo 'PHP ' . PHP_VERSION . ": sotto {$fixed[$branch]}, controlla il pacchetto\n";
} else {
echo 'PHP ' . PHP_VERSION . ": release con la patch\n";
}
Risultato sulla mia macchina: PHP 8.3.6: sotto 8.3.36, controlla il pacchetto. Eppure quel PHP la patch ce l’ha.
Il motivo si chiama backport: alcune distribuzioni Linux con supporto lungo, come Ubuntu, non saltano di release a metà ciclo, prendono la correzione e la innestano sul codice che già distribuiscono. Lo stesso avviso di php.net scrive che distribuzioni e fornitori di supporto esteso hanno ricevuto le patch in anticipo. La pagina di Ubuntu per il CVE riporta per la 24.04 il pacchetto corretto 8.3.6-0ubuntu0.24.04.13: il numero che PHP mostra resta 8.3.6, a cambiare è il suffisso finale. Debian invece per bookworm ha portato il pacchetto direttamente a 8.2.35-1~deb12u1. Due distribuzioni, due abitudini diverse per etichettare lo stesso rimedio.
Per scoprire se quanto è installato include il rimedio si leggono l’etichetta completa del pacchetto e il suo changelog. Qui controllo php8.3-cli; in produzione guarda quello che serve davvero le pagine, cioè php8.3-fpm o libapache2-mod-php8.3:
dpkg -s php8.3-cli | grep '^Version'
# Version: 8.3.6-0ubuntu0.24.04.13
zcat /usr/share/doc/php8.3-cli/changelog.Debian.gz | grep -m1 CVE-2026-109618
# - debian/patches/CVE-2026-109618_109619.patch: Avoid state corruption via
Lo script di prima quindi non è da buttare, va interpretato per quello che è: se dice “release con la patch” per il PHP che serve le pagine (lanciato da terminale controlla la CLI) puoi stare tranquillo, se dice “controlla il pacchetto” devi fare il secondo passo. Vale anche al contrario per gli scanner esterni: un “PHP/8.3.6” nell’header non dimostra che la macchina sia scoperta. E se il tuo aggiornamento porta un numero nuovo (una release di php.net, o Debian con 8.2.35), confronta Salute del sito prima e dopo: se mostra ancora il vecchio, il servizio non è stato riavviato.
Chi deve aggiornare: tu o l’hosting
Su un hosting condiviso il pacchetto PHP lo gestisce il provider. Dal pannello di solito scegli il ramo (8.2, 8.3, 8.4), non la singola release. Qui il tuo lavoro è controllare in Salute del sito quale ramo usi e, se il provider non ha comunicato niente, chiedergli per iscritto se le sue macchine hanno la correzione per CVE-2026-109618 e CVE-2026-109619.
Su un VPS o un server dedicato l’aggiornamento è tuo: sudo apt update && sudo apt upgrade, che porta anche i pacchetti PHP corretti, poi controlla che PHP-FPM o Apache siano stati riavviati (su Debian e Ubuntu di solito ci pensa il pacchetto stesso). Finché un processo resta in memoria, gira con il codice vecchio.
Con i container l’immagine va ricostruita da una base aggiornata e rilasciata di nuovo.
Il 25 ottobre ho fatto la stessa cosa su questo sito, che non usa PHP ma Next.js: npm audit segnalava due vulnerabilità critiche di esecuzione di codice in Next 16.0-16.4.0, e il commit 0574fd2 ha portato il progetto alla 16.4.3. Linguaggio diverso, stessa regola: il runtime è una dipendenza come le altre.
Se non puoi aggiornare subito
L’avviso elenca alcune misure che riducono l’esposizione e precisa che non rendono sicura un’installazione. Servono a guadagnare qualche giorno, non a chiudere la faccenda. Le principali:
- per CVE-2026-109619,
session.upload_progress.enabled=0inphp.inio nella configurazione del pool FPM, con riavvio di tutti i processi. Non funziona se lo imposti conini_set()o con un file.user.ini, perché arriva troppo tardi. Su PHP 8.5 l’avviso aggiungefatal_error_backtraces=0; - per CVE-2026-109618,
memory_limit=-1impostato in modo che l’applicazione non possa sovrascriverlo (di preferenzaphp_admin_valuenel pool FPM o nella configurazione di Apache, controllando che nessun altro pool o cartella rimetta un limite) e unpost_max_sizebasso: 8M se nessuno carica file, 32M se qualcuno lo fa, conupload_max_filesizesotto quel valore.
Il 23 ottobre php.net ha aggiunto un secondo avviso informativo, valido anche per chi ha già aggiornato, che consiglia session.upload_progress.enabled=0 fino alla prossima release ordinaria. Riguarda però solo le applicazioni che cambiano session.serialize_handler durante l’esecuzione: le altre possono lasciare la funzione attiva. Per vedere i valori attivi:
php -i | grep -E '^(memory_limit|post_max_size|upload_max_filesize|session.upload_progress.enabled) '
Anche qui vale il discorso della CLI: php -i legge la configurazione del terminale. Per quella che conta davvero, Salute del sito mostra limite di memoria e dimensioni massime degli upload, ma non session.upload_progress.enabled: per quello serve una pagina phpinfo() temporanea, da cancellare subito dopo.
Un dubbio onesto: memory_limit=-1 toglie il limite di memoria a ogni script, e un plugin scritto male può riempire la RAM di un server piccolo e far cadere tutto. L’avviso stesso suggerisce di usare un limite del container come rete di sicurezza. Io lo userei solo per poche ore e solo su un server che controlli.
Il caso difficile: siti fermi a PHP 7
Per i rami 8.1 e precedenti il progetto PHP non pubblica più release. Per la gravità del caso ha preparato delle correzioni minime in sorgente per 7.4, 8.0 e 8.1, utili a chi compila PHP da sé. Alcune distribuzioni coprono anche i rami vecchi: Ubuntu 22.04, per esempio, ha corretto il suo PHP 8.1 nel pacchetto 8.1.2-1ubuntu2.28. Quindi un 8.1 non è per forza vulnerabile, ma resta un ramo che il progetto PHP non segue più.
L’ostacolo, per un sito su PHP 7, raramente è il pannello dell’hosting. È il codice: il tema o un plugin datato si rompono appena passi al ramo 8. Un esempio classico è create_function(), che il manuale di PHP indica come rimossa dalla versione 8.0:
php -r '$f = create_function("\$a", "return \$a * 2;");'
# PHP Fatal error: Uncaught Error: Call to undefined function create_function() in Command line code:1
Una riga così in functions.php basta a far comparire la schermata di errore critico ovunque. È andata così sul sito WordPress di Crociere Vela Grecia, che seguo in manutenzione: il tema era scritto per PHP 7 e per portarlo a PHP 8.4 ho dovuto correggere più di 20 incompatibilità, tra cui proprio create_function e implode. Il racconto completo è nel case study sulla manutenzione WordPress. WordPress oggi raccomanda PHP 8.3 o superiore, quindi chi è ancora al 7 è indietro due volte.
Se il tuo sito è in questa situazione, l’ordine giusto è: copia completa in staging, cambio di ramo PHP sulla copia, log degli errori acceso, correzione di quello che si rompe, poi passaggio in produzione. Richiede qualche giorno, non un pomeriggio, ed è il genere di lavoro che si rimanda finché una settimana come questa non lo rende urgente. È lo stesso ragionamento di l’illusione della manutenzione zero: il software fermo non resta com’è, invecchia.
Cosa fare oggi
- Apri Strumenti > Salute del sito > Info > Server e annota versione e ramo di PHP.
- Se il numero è uguale o superiore a 8.2.35, 8.3.36, 8.4.27 o 8.5.12 secondo il ramo, le due falle sono chiuse. Resta solo il consiglio del 23 ottobre, se la tua applicazione cambia
session.serialize_handlerdurante l’esecuzione. - Se è più basso, non fermarti al numero: chiedi all’hosting o controlla il changelog del pacchetto come sopra.
- Se sei su 8.1 o precedente, verifica se distribuzione o hosting hanno applicato la correzione, applica le mitigazioni se non è così e pianifica comunque il passaggio di ramo.
- Segna in agenda un controllo mensile: la prossima falla non manderà un preavviso.
Se vuoi capire quanto costa tenere un sito aggiornato senza pensarci tu, nella guida alla manutenzione del sito web trovi cosa comprende e quanto si spende. E se il tuo WordPress è ancora su PHP 7 e non sai da dove partire, scrivimi: guardiamo insieme cosa si rompe prima di cambiare ramo.
Continua a leggere

Sito web statico: perché batte WordPress nel 2026
Pensi che i siti statici siano roba del passato? Scopri come Next.js e la tecnologia JAMstack stanno ridefinendo velocità, sicurezza e costi aziendali.
18 min di lettura
Sicurezza sito web: come proteggere un sito aziendale
Guida alla sicurezza del sito web: come proteggere un sito aziendale da hacker, malware e vulnerabilità mantenendo alte le prestazioni.
17 min di lettura
Manutenzione del sito web: costi, servizi e cosa comprende
Guida alla manutenzione del sito web: costi, servizi ordinari ed evolutivi, tempi di risposta e differenze tra WordPress e Next.js.
16 min di lettura