Riflessioni di un programmatore dopo una giornata passata a ragionare su runtime, mitigazioni e aggiornamenti: ciò che resta quando l’emergenza smette di essere una notizia e diventa manutenzione.
Alla fine di una giornata come questa, la pubblicazione delle patch produce un sollievo molto concreto. Finalmente ci sono versioni da installare, bollettini da leggere, indicazioni sulle quali prendere decisioni. Ma la sensazione che mi resta addosso, dopo aver combattuto con PHP2Shell, è soprattutto la stanchezza di chi conosce la distanza fra un aggiornamento disponibile e un’infrastruttura effettivamente aggiornata. Dentro quella distanza ci sono hosting, configurazioni, dipendenze, compatibilità, applicazioni che nessuno vuole fermare e responsabilità che diventano improvvisamente visibili. Chi scrive software e poi continua a mantenerlo conosce bene questo momento: la notizia passa, il lavoro rimane.
Il 21 ottobre il progetto PHP ha pubblicato le versioni 8.2.35, 8.3.36, 8.4.27 e 8.5.12, che correggono CVE-2026-109618 e CVE-2026-109619. Il bollettino invita ad aggiornare immediatamente e considera a rischio le installazioni che servono richieste web, comprese quelle basate su PHP-FPM, mod_php, CGI, FrankenPHP e LiteSpeed. Il rischio più elevato viene attribuito a mod_php, per il quale è stato dimostrato un attacco senza autenticazione che interviene prima dell’esecuzione del codice applicativo. 1 È una precisazione che pesa, perché toglie terreno a una rassicurazione molto comune: avere scritto bene la propria applicazione non basta a mettere al sicuro l’interprete che la esegue.
Quando lavoro a un progetto posso controllare una query, validare un parametro, rivedere un’autorizzazione e correggere una gestione sbagliata dei file. Posso perfino costruirmi un modello ragionevolmente dettagliato di quello che accade dal primo middleware all’ultima risposta. Poi arriva una vulnerabilità del runtime e quel modello rivela il proprio confine: sotto l’applicazione esiste altro software, con un ciclo di vita della richiesta, strutture di memoria e percorsi di errore sui quali il mio codice poggia senza governarli. Una giornata del genere serve anche a ricordare quanto sia limitata l’espressione “il mio sito è aggiornato”, quando con quella frase si intende soltanto il CMS o l’ultimo deploy.
Adesso i dettagli consentono anche di correggere le semplificazioni circolate durante l’attesa. La prima vulnerabilità riguarda la gestione delle condizioni di esaurimento della memoria. Un’uscita anticipata tramite longjmp() può lasciare dati interni parzialmente inizializzati, che le operazioni di chiusura della richiesta finiscono per trattare come validi. La correzione modifica questa gestione introducendo un esaurimento controllato della memoria nei punti sicuri della macchina virtuale e una terminazione immediata oltre una seconda soglia. 2 Per un programmatore, il dettaglio interessante è proprio questo: anche il codice che deve gestire il fallimento ha bisogno di invarianti solide. Se il percorso di emergenza può osservare oggetti incompleti, l’eccezione smette di essere una semplice interruzione del lavoro e diventa un problema di integrità del processo.
La seconda vulnerabilità riguarda invece stato globale che può sopravvivere alla memoria della richiesta cui apparteneva. Un worker persistente gestisce richieste successive; se conserva un riferimento ormai invalido, un’operazione successiva può utilizzarlo prima che la normale inizializzazione lo azzeri. Il risultato è un use-after-free. Il tracciamento dell’avanzamento degli upload è uno dei percorsi confermati, ma il problema coinvolge più in generale il rapporto fra stato, errori e confini delle richieste. 3 È una di quelle lezioni che dovrebbero accompagnare qualsiasi sviluppo con processi persistenti: la risposta HTTP è finita, ma il processo continua a vivere, e ogni cosa che si porta dietro deve avere un proprietario e una durata chiaramente definiti.
Durante l’attesa, l’attenzione si era concentrata sulla direttiva session.upload_progress.enabled. Disabilitare una funzione inutilizzata era una decisione preventiva comprensibile, ma ora bisogna leggere le indicazioni aggiornate: spegnerla blocca i percorsi di sessione confermati, senza coprire tutte le varianti. Il bollettino richiede una configurazione applicata prima del parsing e il riavvio di tutti i worker; per PHP-FPM avverte espressamente di non affidarsi a .user.ini, oltre che a ini_set(). 1 Questo aggiorna anche il ragionamento del mio articolo precedente. Nell’emergenza dobbiamo essere capaci di intervenire con le informazioni disponibili e poi rivedere l’intervento quando quelle informazioni diventano più precise. Difendere una configurazione perché l’abbiamo suggerita qualche ora prima sarebbe soltanto un altro modo di perdere tempo.
È qui che sento maggiormente la differenza fra commentare una vulnerabilità e doverla gestire. Da fuori sembra sufficiente trovare la riga giusta da incollare. Da dentro devi sapere dove quella riga viene letta, quando entra in vigore, quale processo la eredita e che cosa può sovrascriverla. Devi distinguere il PHP della shell dal PHP che risponde al browser; un valore mostrato nel pannello dalla configurazione realmente utilizzata dal pool; un pacchetto scaricato da un worker che sta ancora eseguendo il vecchio binario. Sono passaggi poco spettacolari, difficili da condensare in un post, ma è lì che una misura smette di essere un’intenzione e diventa una proprietà verificabile del sistema.
Anche le mitigazioni ufficiali contro il problema OOM richiedono attenzione. Il progetto indica, per chi non può aggiornare subito, l’imposizione amministrativa di memory_limit=-1, accompagnata da limiti sugli input e da confini di disponibilità esterni al runtime. L’advisory chiarisce però che i fallimenti dell’allocatore sottostante possono ancora raggiungere il percorso vulnerabile e sconsiglia RLIMIT_AS e RLIMIT_DATA. 2 Sarebbe irresponsabile estrarre da questo contesto soltanto “togliete il limite di memoria” e trasformarlo in una ricetta universale. La gestione di una vulnerabilità può spostare il rischio fra esecuzione del codice, consumo di risorse e disponibilità: per questo una mitigazione temporanea richiede comprensione, verifica e una scadenza.
Resto quindi convinto del punto da cui ero partito: ridurre l’esposizione prima dell’arrivo delle patch aveva senso. Quella scelta comprava tempo. Adesso che le correzioni esistono, quel tempo va usato per installarle. La misura provvisoria non dovrebbe diventare l’ennesima eccezione permanente di cui ci ricorderemo soltanto alla prossima emergenza. Vorrei vedere una maggiore capacità di chiudere davvero questi interventi: sapere che cosa abbiamo cambiato, quali servizi sono stati verificati, chi deve completare il lavoro e quali configurazioni temporanee dovranno essere riesaminate.
C’è poi un aggiornamento importante per chi è rimasto sulle versioni vecchie. PHP 8.1 e precedenti restano fuori dal supporto ordinario del progetto, ma, data la gravità delle vulnerabilità, il team ha fornito backport sorgente minimi per PHP 7.4, 8.0 e 8.1. Esistono inoltre correzioni distribuite secondo le politiche dei fornitori e dei servizi LTS. 1 È una possibilità concreta che va segnalata, correggendo qualsiasi formula troppo assoluta sull’assenza di rimedi per il legacy. Un backport straordinario, però, non equivale alla riapertura della manutenzione: offre una via di uscita dall’emergenza attuale, mentre il problema del ciclo di vita rimane.
Non mi interessa liquidare chi mantiene software vecchio con la solita battuta sul gestionale preistorico. So quanto facilmente una migrazione possa incagliarsi in un’estensione, in una dipendenza abbandonata o in una funzione commerciale che nessuno ha il budget di riscrivere. Ma proprio perché queste difficoltà sono reali, andrebbero affrontate prima di ritrovarsi con una vulnerabilità critica e poche ore per decidere. Quando ogni aggiornamento sembra impraticabile, abbiamo già perso una parte importante del controllo sul progetto. Il debito tecnico si manifesta anche così: attraverso operazioni ordinarie che diventano troppo costose, finché un’emergenza obbliga a pagarle tutte insieme.
La parte che merita più attenzione arriva però dal resoconto della PHP Foundation. I primi segnali del problema OOM erano emersi nel 2024; le possibili correzioni comportavano compromessi su compatibilità, prestazioni ed estensioni. La Foundation riconosce che il lavoro si era arenato e descrive il ritardo come un fallimento strutturale, legato al processo decisionale e alla scarsità di risorse. 4 È un’ammissione seria. Leggerla dovrebbe spingerci a chiedere che cosa stiamo facendo, come aziende e professionisti, per sostenere le persone dalle quali dipendono i nostri servizi.
Facciamo preventivi per sviluppare prodotti sopra questi runtime, vendiamo abbonamenti, realizziamo portali e incassiamo per mantenerli. Poi il lavoro più profondo, quello che richiede di conoscere il motore e di scegliere fra correzioni tutte difficili, rischia di rimanere concentrato su pochissime persone. Posso pretendere trasparenza e tempestività da un progetto essenziale e, nello stesso momento, riconoscere che quella tempestività richiede finanziamenti, continuità e capacità decisionale. La gratitudine verso i manutentori serve a poco se non cambia mai il modo in cui distribuiamo risorse e responsabilità.
Stasera le patch ci sono e il lavoro deve proseguire fino a raggiungere i sistemi che servono davvero le richieste, comprese le immagini e le procedure che useremo per ricrearli domani. Ma quello che vorrei portarmi fuori da questa giornata è una richiesta più semplice e più scomoda: trattare la manutenzione come parte del prodotto, anche quando non c’è una CVE a renderla urgente. Voglio poter aggiornare un runtime senza dover riscoprire l’infrastruttura da zero. Voglio che il tempo speso a mantenere una dipendenza venga considerato lavoro utile prima che diventi lavoro d’emergenza. E vorrei che, passata la stanchezza di oggi, restasse almeno la volontà di pagare quel costo con regolarità.
Fonti primarie verificate il 21 ottobre 2026:
PHP — Security advisory: Critical remote code execution vulnerabilities, update now ↩ ↩ ↩
PHP — RCE via OOM corruption, CVE-2026-109618 ↩ ↩
PHP — RCE via stale global state, CVE-2026-109619 ↩
The PHP Foundation — Today’s PHP Security Release, and How We’re Strengthening PHP Security ↩