wp2shell: la catena che trasforma due bug del core WordPress in una shell non autenticata

wp2shell è il nome con cui la community di sicurezza indica una catena di due vulnerabilità nel core di WordPress, CVE-2026-63030 e CVE-2026-60137, che combinate permettono di eseguire codice arbitrario su un sito senza alcuna autenticazione. Non serve un plugin vulnerabile, non serve un account compromesso: basta che il sito giri su una versione di WordPress non aggiornata. È per questo che, a differenza della maggior parte degli avvisi di sicurezza su WordPress, qui il problema è nel cuore del CMS, non nell'ecosistema di terze parti che lo circonda.

Indice


Le due vulnerabilità

CVE-2026-63030: route confusion nella REST API batch

Dalla versione 6.9, WordPress espone di default l'endpoint /wp-json/batch/v1, pensato per eseguire più sotto-richieste REST in un'unica chiamata HTTP: utile, ad esempio, per aggiornare più oggetti in un colpo solo senza il costo di round trip multipli. Il bug scoperto da Adam Kues di Assetnote, la divisione attack surface management di Searchlight Cyber, sta nel modo in cui il batch endpoint tiene traccia di quale sotto-richiesta appartiene a quale handler interno. Un input malformato in una delle sotto-richieste disallinea i due array che il codice usa per abbinare richieste e gestori, e il risultato è che una richiesta finisce per essere eseguita sotto il permission model di un endpoint diverso da quello a cui era realmente indirizzata. In pratica, un chiamante anonimo riesce a far eseguire al server una chiamata REST che dovrebbe richiedere permessi che non ha.

CVE-2026-60137: SQL injection in WP_Query

La seconda falla, segnalata separatamente dai ricercatori TF1T, dtro e haongo, riguarda il parametro author__not_in di WP_Query, la classe che WordPress usa ovunque per costruire query sui contenuti. Quel parametro dovrebbe accettare solo un array di ID numerici, ma se gli viene passata una stringa il controllo di tipo viene bypassato e il valore finisce concatenato direttamente nella clausola SQL, senza sanitizzazione. È il classico difetto da SQL injection: un parametro pensato per contenere solo numeri che invece accetta testo libero e lo tratta come fidato.

Presa da sola, questa seconda falla è già sfruttabile dalla versione 6.8 in poi, ma richiede comunque un punto d'accesso che permetta di raggiungere WP_Query con parametri controllati dall'attaccante. Ed è esattamente quello che fornisce la prima vulnerabilità.

Come si incatenano: dalla REST API alla shell

Il meccanismo che rende wp2shell pericoloso non è la somma delle due falle, è la loro sequenza. La route confusion nel batch endpoint permette di contrabbandare input non autenticato fino al punto in cui viene costruita la query WP_Query, e lì il parametro author__not_in malformato inietta SQL arbitrario nel database. Da una SQL injection alla cieca, l'attaccante può leggere hash delle password e dati sensibili tramite query UNION, ma il salto verso l'esecuzione di codice passa da un'altra strada: usando l'injection per scrivere righe nella cache degli oEmbed, è possibile far apparire nel database un post fabbricato che WordPress tratta come legittimo. Da lì la catena prosegue verso la creazione di un account con privilegi di amministratore che non è mai passato dal normale flusso di registrazione, e con quell'account è banale caricare un plugin creato ad hoc che altro non è che una web shell in PHP.

Il punto debole del sistema, in questo caso, non è un singolo controllo mancante ma la fiducia implicita tra componenti interni: il batch endpoint si fida del router, il router si fida del validatore, il validatore si fida del tipo di dato in ingresso. Basta rompere un anello per far scorrere dati non fidati fino in fondo alla catena, e in questo caso quell'anello permette di saltare completamente l'autenticazione.

Timeline della disclosure

Data Evento
6.9 (release) viene introdotto il batch endpoint /wp-json/batch/v1, base della route confusion.
6.8 (release) il parametro author__not_in di WP_Query è già vulnerabile alla SQL injection, ma senza un vettore non autenticato che lo raggiunga.
17 luglio 2026 Searchlight Cyber pubblica la ricerca completa e coordina la disclosure con il team di sicurezza di WordPress.org.
17-18 luglio 2026 WordPress.org rilascia le versioni con la patch e attiva gli aggiornamenti automatici forzati sulle installazioni supportate.
18 luglio 2026 iniziano a comparire i primi proof of concept pubblici su GitHub, nel giro di ore dalla disclosure.
20 luglio 2026 decine di repository con exploit pronti all'uso circolano pubblicamente; più fonti di settore segnalano scansioni di massa alla ricerca di installazioni non aggiornate.

Versioni coinvolte

Versione Esposizione Versione con la patch
6.8.0 - 6.8.5 solo CVE-2026-60137 (SQL injection, senza il vettore REST non autenticato) 6.8.6
6.9.0 - 6.9.4 catena completa, RCE non autenticata 6.9.5
7.0.0 - 7.0.1 catena completa, RCE non autenticata 7.0.2
7.1.0 beta catena completa 7.1.0 beta 2

Le installazioni sulle versioni 6.8.x restano esposte alla sola SQL injection, che di per sé permette già di leggere dati sensibili dal database: non è un problema da derubricare solo perché manca l'ultimo anello della catena verso l'RCE.

Sfruttamento in corso

wp2shell non è, al momento della stesura, nel catalogo KEV di CISA, che elenca solo vulnerabilità con sfruttamento confermato e documentato. Questo però dice poco sulla situazione reale: nel giro di poche ore dalla pubblicazione della ricerca, su GitHub sono comparsi diversi repository con exploit funzionanti, alcuni pensati per singolo target, altri per scansioni bulk su liste di siti. Diversi ricercatori hanno notato come strumenti di sviluppo assistiti da IA abbiano accorciato drasticamente il tempo necessario per trasformare l'advisory tecnico in codice d'attacco pronto all'uso, un pattern che si sta ripetendo su sempre più CVE ad alto impatto.

Il fatto che il bug sia nel core, e non in un plugin di terze parti, amplia enormemente la superficie: qualunque installazione WordPress con zero plugin attivi, in una versione vulnerabile, è comunque attaccabile.

Come verificare se il tuo sito è a rischio

Il primo controllo è la versione installata:

wp core version

Se il numero restituito rientra in uno degli intervalli vulnerabili elencati sopra, il sito va aggiornato immediatamente:

wp core update
wp core update-db

Chi gestisce WordPress da pannello può controllare la versione da Bacheca > Aggiornamenti. Vista la gravità, WordPress.org ha forzato l'aggiornamento automatico sulle installazioni supportate, ma vale la pena verificarlo comunque: siti con WP_AUTO_UPDATE_CORE disabilitato in wp-config.php, hosting con configurazioni particolari o installazioni gestite manualmente potrebbero non aver ricevuto la patch in automatico.

Searchlight Cyber ha reso disponibile uno strumento pubblico di verifica su wp2shell.com, ed Eye Security distribuisce un'estensione browser e un plugin WordPress (Compromise Scanner) pensati rispettivamente per il check della versione esposta e per l'analisi di eventuali artefatti di compromissione già presenti.

Mitigazioni se non puoi aggiornare subito

L'aggiornamento a 6.8.6, 6.9.5 o 7.0.2 resta l'unica soluzione definitiva. Se per qualche motivo non è possibile applicarlo nell'immediato, la misura tampone più efficace è impedire l'accesso non autenticato al batch endpoint, tenendo conto che il percorso può essere raggiunto sia come path REST diretto sia tramite il parametro di query rest_route sulle installazioni senza permalink "pretty".

Su Nginx:

location ~ ^/wp-json/batch/v1 {
    deny all;
    return 403;
}
if ($args ~* "rest_route=/batch/v1") {
    return 403;
}

Su Apache, via .htaccess:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/wp-json/batch/v1 [NC,OR]
RewriteCond %{QUERY_STRING} rest_route=/batch/v1 [NC]
RewriteRule .* - [F,L]
</IfModule>

Cloudflare ha attivato regole WAF per questa catena su tutti i piani, incluso quello gratuito, quindi chi già passa dal loro proxy ha una protezione aggiuntiva senza dover intervenire manualmente. Vale comunque la pena verificare che le regole siano effettivamente in modalità "block" e non solo "log".

Un dettaglio utile per chi gestisce infrastrutture più grandi: un object cache persistente come Redis o Memcached rende meno affidabile per l'attaccante la parte finale della catena legata alla cache degli oEmbed, ma non offre alcuna protezione contro la SQL injection di base, che resta comunque sfruttabile per esfiltrare dati.

Se sospetti una compromissione

Chi ha lasciato il sito esposto tra il 17 e il 20 luglio 2026 dovrebbe verificare la presenza di indicatori di compromissione, non limitarsi ad applicare la patch. Gli account amministratore creati dagli exploit pubblici tendono a usare prefissi riconoscibili come wp2_ o w2s_, retaggio del nome stesso della catena d'attacco:

SELECT ID, user_login, user_email, user_registered
FROM wp_users
WHERE user_login LIKE 'wp2\_%' OR user_login LIKE 'w2s\_%'
ORDER BY user_registered DESC;

Vale la pena controllare anche righe anomale nella cache degli oEmbed, usate nella fase intermedia della catena per fabbricare contenuti fidati:

SELECT option_id, option_name, LEFT(option_value, 200) AS preview
FROM wp_options
WHERE option_name LIKE '\_oembed\_%'
ORDER BY option_id DESC
LIMIT 50;

Sul filesystem, cercare plugin caricati o modificati dopo la finestra di disclosure aiuta a individuare eventuali web shell:

find wp-content/plugins -name "*.php" -newermt "2026-07-16" -type f

Se emerge uno di questi indicatori, non basta cancellare il plugin sospetto o l'account rogue: le credenziali di database, le chiavi di autenticazione in wp-config.php e le password di tutti gli utenti con ruolo amministratore vanno ruotate, perché la SQL injection alla base della catena ha permesso di leggere dati dal database ben prima che comparisse qualunque traccia visibile.

Perché un bug nel core cambia le regole

La maggior parte degli avvisi di sicurezza su WordPress riguarda plugin di terze parti, spesso mantenuti da singoli sviluppatori con risorse limitate, ed è per questo che la prassi consolidata è ridurre il numero di plugin attivi e tenerli aggiornati. wp2shell ribalta quella logica: qui il codice vulnerabile è quello che gira su ogni singola installazione WordPress, indipendentemente da quanto sia minimale la configurazione. Un sito con il solo tema di default e zero plugin è comunque esposto, il che rende inutile qualunque strategia di riduzione della superficie basata sui plugin.

È anche un promemoria di come la REST API, ormai parte integrante del core dal 2016, resti una delle zone del codice più difficili da validare in modo esaustivo: espone funzionalità pensate per essere componibili, e la composizione è proprio il terreno in cui i controlli di autorizzazione tendono a rompersi in modi che i test unitari sui singoli endpoint non intercettano.

Risorse

  1. Searchlight Cyber - wp2shell research
  2. WordPress.org - Security release 6.9.5
  3. The Hacker News - New wp2shell WordPress Core Flaw
  4. Eye Security - wp2shell: a defender's guide
  5. Tenable - wp2shell FAQ
  6. OWASP Cheat Sheet - SQL Injection Prevention