DIEGO CECATO / NOTE DAL CAMPO

PHP2Shell: la patch installata non è la patch attiva

diego cecato//
Copertina PHP2Shell: la patch installata non è la patch attiva, geometrie rettilinee blu e ritratto Diego Cecato

Puoi avere WordPress aggiornato, plugin revisionati, un tema scritto con criterio e perfino una discreta disciplina di deploy. Poi scopri che il problema è nel motore che esegue tutto questo. Non nel codice che hai scritto, non in una dipendenza che hai dimenticato, ma in PHP stesso. È una distinzione poco rassicurante, perché sposta la responsabilità fuori dal perimetro che molti sviluppatori controllano ogni giorno.

Il 21 ottobre 2026 il progetto PHP ha rilasciato 8.5.12, 8.4.27, 8.3.36 e 8.2.35 per correggere due vulnerabilità critiche, CVE-2026-109618 e CVE-2026-109619, che possono consentire esecuzione remota di codice senza autenticazione. L’avviso ufficiale PHP invita ad aggiornare immediatamente. La notizia merita attenzione, ma la domanda interessante per chi gestisce sistemi non è soltanto “quale versione devo installare?”. È un’altra: quale processo PHP sta davvero rispondendo alle richieste del mio sito, adesso?

La falla non è in WordPress. Ed è proprio questo il problema

L’avviso di WordPress.org è esplicito: per questi difetti non serve un aggiornamento del core WordPress. Serve correggere PHP. Un aggiornamento del CMS, del tema o di un plugin non modifica automaticamente il runtime installato sul server. Confondere i livelli significa fare manutenzione nel punto sbagliato, magari con l’illusione di aver chiuso un rischio che continua a esistere sotto l’applicazione.

Questa è una delle conseguenze più concrete dell’architettura a strati. Il codice applicativo decide che cosa fare quando una richiesta arriva al framework o al CMS. Ma prima di quel momento il server web e l’interprete hanno già eseguito operazioni proprie: inizializzazione, gestione degli input, allocazione della memoria, preparazione del contesto. Se il difetto è lì, le migliori validazioni scritte in PHP potrebbero non essere ancora state eseguite. Non significa che ogni configurazione sia sfruttabile allo stesso modo; significa che il confine di protezione dell’applicazione non coincide con quello del processo che la ospita.

Due vulnerabilità, un denominatore comune: lo stato interno

I due advisory pubblicati dal progetto PHP descrivono problemi distinti. CVE-2026-109618 riguarda la gestione di condizioni di memoria esaurita: un’interruzione in una fase delicata può lasciare strutture interne non completamente inizializzate, che vengono poi trattate come valide durante la chiusura della richiesta. CVE-2026-109619 riguarda invece riferimenti a stato appartenente a una richiesta che sopravvivono oltre la liberazione della memoria e possono essere riutilizzati da un worker in una richiesta successiva.

Il punto comune non è una funzione WordPress mal progettata. È il ciclo di vita delle richieste e il modo in cui il runtime conserva, ripulisce e riutilizza il proprio stato. Gli advisory distinguono anche fra modalità di esecuzione: per Apache con mod_php esiste una dimostrazione di compromissione attraverso HTTP; per altri ambienti, inclusi PHP-FPM e le integrazioni alternative, condizioni e grado di dimostrazione cambiano. Trasformare questa distinzione in “ogni sito PHP è già compromesso” sarebbe un salto logico. Ignorarla perché “noi usiamo FPM” sarebbe un salto altrettanto poco giustificato.

Il progetto PHP è netto anche sulle contromisure: le modifiche di configurazione possono ridurre alcuni percorsi di rischio, ma non sostituiscono una versione corretta. Un WAF, allo stesso modo, può essere un livello di contenimento; non diventa per magia una patch del motore.

La patch scaricata non è necessariamente quella in esecuzione

Qui arriviamo al problema che nelle aziende si nasconde dietro una spunta verde. Il package manager segnala che l’aggiornamento è riuscito. Il pannello dell’hosting mostra una versione. La pipeline termina senza errori. Tutto corretto, forse. Ma un processo già avviato può continuare a usare il codice che aveva caricato prima dell’aggiornamento, finché non viene riavviato o sostituito. Canonical lo ricorda espressamente nelle indicazioni per PHP2Shell: dopo l’installazione dei pacchetti, il servizio che usa l’interprete potrebbe richiedere un riavvio.

Non è un dettaglio burocratico. È la differenza tra lo stato desiderato del sistema e quello realmente osservabile. Una dashboard che registra “aggiornamento installato” risponde a una domanda; una verifica del processo che serve le richieste ne risponde a un’altra. Se mescoliamo le due, stiamo misurando l’esecuzione di una procedura e la chiamiamo sicurezza.

La sicurezza non coincide con il comando eseguito. Coincide con lo stato verificato del sistema che continua a lavorare dopo quel comando.

La versione di PHP da terminale può essere quella sbagliata

C’è poi una trappola familiare a chi gestisce più siti o più versioni dello stesso linguaggio. Il comando php -v descrive l’interprete disponibile in quella sessione di terminale. Non dimostra automaticamente quale binario, pool o processo venga usato dal server web. Su una macchina possono convivere CLI, PHP-FPM con pool diversi, mod_php, container e runtime gestiti dal provider. A volte le versioni coincidono; altre volte no.

Per un sito WordPress il controllo più vicino all’applicazione passa da Strumenti → Salute del sito → Informazioni → Server, come indica WordPress.org. È un buon punto di partenza, da confrontare con il pannello dell’hosting e con l’inventario dei processi o dei container effettivamente in servizio. Su ambienti gestiti il dato va chiesto al fornitore con precisione: versione del runtime web, pacchetto corretto applicato, istanze riavviate e data dell’intervento. Non basta uno screenshot del terminale di un server che magari non serve neppure quel dominio.

Attenzione anche all’opposto: non è necessario pubblicare una pagina di diagnostica con tutti i dettagli di PHP per dimostrare che si è aggiornato. Le informazioni tecniche utili all’amministratore non devono diventare automaticamente informazioni esposte a chiunque visiti il sito.

I backport Linux rendono ingannevole il confronto dei numeri

Le versioni upstream corrette sono chiare. Ma i pacchetti delle distribuzioni non seguono sempre lo stesso numero. Un fornitore può mantenere la versione di base e incorporare la correzione nel proprio pacchetto, preservando compatibilità con la distribuzione. Per esempio, l’advisory Ubuntu USN-8948-1 elenca per Ubuntu 24.04 un pacchetto PHP 8.3 con numero di versione della distribuzione differente da PHP 8.3.36 upstream.

Questo significa che un semplice confronto lessicografico con “8.3.36” può generare due errori opposti: dichiarare insicuro un pacchetto già corretto dal vendor oppure considerare sufficiente un numero di versione senza verificare che il pacchetto installato contenga davvero la patch. La fonte autorevole, in quel caso, è l’advisory del fornitore insieme alla versione completa del pacchetto e alla sua provenienza. Non il numero mostrato in grande da un plugin.

Il caso diventa ancora più delicato sulle versioni fuori dal supporto ordinario del progetto PHP. L’esistenza di backport o supporto esteso presso alcuni vendor non equivale a una garanzia universale per qualsiasi installazione legacy. Anche qui serve un inventario, non una supposizione.

Un controllo serio ha quattro passaggi, non una spunta

1. Sapere dove gira PHP

Elenca i siti e i servizi esposti, poi associa ciascuno al runtime effettivo: versione, modalità di esecuzione, pool, container, host e responsabilità del fornitore. L’inventario deve descrivere la richiesta reale che arriva al sito, non soltanto ciò che è installato sulla macchina.

2. Collegare ogni runtime al proprio advisory

Per installazioni upstream verifica le release corrette pubblicate dal progetto PHP. Per pacchetti di distribuzione controlla gli avvisi del vendor e la versione completa installata. Evita di interpretare l’assenza di una versione upstream identica come prova automatica di vulnerabilità o sicurezza.

3. Distribuire la correzione e sostituire i processi

Pianifica l’intervento in base alla criticità dei servizi, applica gli aggiornamenti attraverso i normali canali del sistema e assicurati che i processi coinvolti vengano effettivamente sostituiti o riavviati secondo le indicazioni del provider. Su ambienti con più nodi o container, la verifica deve riguardare tutte le istanze che possono ricevere traffico. Una sola istanza rimasta indietro è sufficiente a rendere falso il messaggio “abbiamo aggiornato tutto”.

4. Verificare il servizio, non soltanto l’installazione

Dopo l’intervento controlla che il sito risponda, che la versione e il pacchetto serventi siano quelli attesi, che non restino worker obsoleti e che i log non mostrino regressioni applicative. Registra evidenze e orario della verifica. Se il sito è gestito da terzi, chiedi una conferma tecnica verificabile, non una rassicurazione generica.

Chi possiede il runtime possiede anche la responsabilità

PHP2Shell rende visibile una dipendenza che spesso rimane implicita nel rapporto fra sviluppatore, agenzia e hosting. Chi aggiorna il codice? Chi gestisce l’interprete? Chi può riavviare i worker? Chi sa verificare che tutti i nodi stiano usando la correzione? Sono quattro domande diverse e non sempre hanno la stessa risposta. Se nessuno le ha messe nero su bianco, l’incidente non crea il problema organizzativo: lo rivela.

È lo stesso genere di fragilità che emerge quando una dipendenza software non ha una manutenzione assegnata, oppure quando un’applicazione viene spostata in un’infrastruttura che cambia gli assunti operativi. L’architettura non finisce nel repository. Comprende chi governa ciò che il repository dà per scontato.

Non serve trasformare ogni sviluppatore in un amministratore di sistema. Serve però smettere di considerare l’hosting una scatola astratta. Quando un componente di base è vulnerabile, sapere dove finisce la responsabilità del codice e dove inizia quella dell’infrastruttura è parte della capacità di intervenire. Non una nota contrattuale da recuperare quando ormai è tardi.

La lezione di questo rilascio non è che WordPress sia insicuro, né che PHP sia da abbandonare. È più concreta e meno comoda: una patch ha valore soltanto quando sappiamo dimostrare che il servizio che conta la sta realmente eseguendo. Il resto, per quanto ordinato appaia sul pannello di controllo, è un’ipotesi.

Domande frequenti

Devo aggiornare WordPress per correggere PHP2Shell?

No. Le vulnerabilità sono nel runtime PHP: WordPress.org chiarisce che non è richiesto un aggiornamento del core per queste specifiche correzioni. Occorre aggiornare il PHP effettivamente utilizzato dal sito.

Quali versioni upstream PHP includono le correzioni?

Le release pubblicate il 21 ottobre 2026 sono PHP 8.5.12, 8.4.27, 8.3.36 e 8.2.35. Su Linux gestito da una distribuzione possono esistere backport con numerazioni differenti.

Perché php -v non basta a controllare il mio sito?

php -v mostra l’interprete della sessione CLI. Il sito può utilizzare un pool PHP-FPM, un modulo Apache, un container o un’altra installazione. Va verificato il runtime che serve le richieste web.

Un WAF o una modifica di configurazione sostituisce l'aggiornamento?

No. PHP segnala che le mitigazioni di configurazione sono parziali e non equivalgono alle correzioni ufficiali. Anche il WAF può ridurre alcuni percorsi di esposizione, ma non corregge il runtime.

Perché occorre controllare i processi dopo l'aggiornamento?

L’installazione del pacchetto non prova da sola che ogni processo web in esecuzione utilizzi il codice aggiornato. Occorre verificare riavvii o sostituzioni dei worker, soprattutto su ambienti con più istanze.