Il 17 luglio WordPress ha rilasciato la 7.0.2, con i backport 6.9.5, 6.8.6 e 7.1 Beta 2, per chiudere una catena di due bug del core battezzata WP2Shell: esecuzione di codice remoto senza autenticazione su un'installazione di default, senza plugin e senza account. I primi tentativi sono arrivati la sera stessa. La patch è stata la parte facile.
La catena in due righe
CVE-2026-60137 è una SQL injection nel parametro author__not_in di WP_Query. CVE-2026-63030 è un errore logico di route confusion nel batch processor della REST API, su /wp-json/batch/v1: validazione ed esecuzione girano in due loop separati e, quando wp_parse_url() fallisce sul path di una sotto-richiesta, l'errore finisce nell'array di validazione ma non in quello dei match. I due array si disallineano e ogni richiesta successiva viene eseguita dall'handler sbagliato. Il risultato: una richiesta anonima arriva dove non dovrebbe e la SQL injection diventa sfruttabile senza autenticazione. Da lì si forgia un amministratore, si entra e si carica un plugin malevolo. Colpite le versioni da 6.9.0 a 6.9.4 e da 7.0.0 a 7.0.1 per la catena completa, da 6.8.0 a 6.8.5 per la sola SQL injection; prima della 6.8 nessuna esposizione. Il bug del batch è di Adam Kues (Assetnote, Searchlight Cyber), la SQL injection di TF1T, dtro e haongo.
Le etichette di gravità non concordano
L'advisory ufficiale parla di un problema critico e uno alto. Rapid7 definisce critica la RCE ma le assegna un CVSS 7.5, Tenable la valuta 9.8. Non perdeteci tempo: la gravità qui è della catena, non dei singoli anelli.
La finestra reale è stata di ore
Patchstack ha segnalato tentativi poco prima delle 19:00 ET dello stesso 17 luglio. Cloudflare aveva già pubblicato due regole WAF alle 17:03 UTC, con azione predefinita di blocco, attive anche sui piani gratuiti. Il 19 luglio VulnCheck aveva verificato più di due dozzine di PoC pubblici distinti, il 20 osservava sfruttamento contro sistemi in produzione, il 21 entrambe le CVE erano nel catalogo KEV della CISA. WordPress.org ha fatto una cosa rara: ha forzato l'aggiornamento automatico sui siti vulnerabili.
Cosa abbiamo controllato, in quest'ordine
- Versione reale, non presunta: l'update forzato copre molto ma non tutto. Host gestiti, plugin che pinnano il core e aggiornamenti disattivati anni fa da qualcun altro restano indietro finché non interviene una persona.
- Superficie REST: verificare se
/wp-json/batch/v1risponde agli anonimi. Su un sito vetrina non serve a nessuno, e chiudere l'accesso REST anonimo non costa niente. - Log HTTP: cercare richieste al batch endpoint nei giorni intorno al 17 luglio. È l'unico modo per distinguere "non attaccato" da "non guardato".
- Diff dopo la patch: utenti amministratori, directory dei plugin, cartella uploads, file PHP comparsi dal nulla. Aggiornato e pulito sono due stati diversi.
Verdetto
L'aggiornamento automatico del core non è più una preferenza, è un requisito minimo: chi lo disattiva si assume un rischio che non sa quantificare. Ma il problema strutturale è un altro, e nessuna patch lo risolve: troppi siti PMI non hanno nessuno il cui lavoro sia applicarla. Se il vostro non era aggiornato entro 48 ore dal 17 luglio, non chiedetevi se è stato colpito: date per scontato che lo sia e fate il diff. E chiudete la REST API agli anonimi, perché è la superficie che continua a produrre incidenti di questa taglia.