La falla CSRF di Elementor trasforma un link cliccato in un account amministratore
Una vulnerabilità di tipo cross-site request forgery (CSRF) nel plugin Elementor Website Builder consente a un singolo link, aperto da un utente WordPress autenticato, di far eseguire a quell'utente qualsiasi azione dell'API REST che il suo account è autorizzato a compiere. In un'installazione WordPress standard, un amministratore che clicca sul link crea un secondo account amministratore per l'attaccante. La vulnerabilità interessa esattamente le versioni 4.3.0 e 4.3.1, e solo queste due release. È stata scoperta e segnalata a Patchstack dal ricercatore di sicurezza Saggre, e Patchstack ha emesso regole di mitigazione per proteggere dallo sfruttamento. La falla ha un punteggio CVSS di 8.8, collocandola nella fascia di gravità alta.
Elementor è il page builder più diffuso per WordPress, attivo su oltre dieci milioni di siti. Offre un editor visuale drag-and-drop, una libreria di template e un theme builder per costruire pagine senza scrivere codice. Il codice vulnerabile appartiene al modulo Editor Events, che fa da proxy per la telemetria dell'editor di Elementor. Questo modulo è controllato da un esperimento, ma non in un modo che la maggior parte dei proprietari di siti può vedere o influenzare. L'esperimento è contrassegnato come nascosto, quindi non appare affatto nella schermata Experiments di Elementor, e la sua impostazione default_active lo attiva per ogni sito la cui prima installazione di Elementor sia la versione 3.32.0 o successiva. Un'installazione predefinita di 4.3.0 o 4.3.1, senza modifiche alle impostazioni e senza altri plugin presenti, è vulnerabile. Il costruttore del modulo registra inoltre il filtro rilevante incondizionatamente, quindi nulla nelle impostazioni di telemetria del sito impedisce la vulnerabilità. Le release precedenti alla 4.3.0 non includono affatto il proxy Editor Events e non sono interessate.
Il proxy degli eventi registra due route REST e vuole che le proprie richieste siano esentate dal controllo nonce REST, che è la protezione integrata di WordPress core contro CSRF. Per farlo, aggancia il filtro rest_authentication_errors con priorità 0. Il problema è il tempismo: questo filtro viene eseguito prima che WordPress abbia abbinato una route, quindi la callback può solo ispezionare la stringa grezza dell'URI della richiesta. Il codice usa una ricerca strpos() non ancorata sull'intero $_SERVER['REQUEST_URI'], che include sia il percorso sia la query string. Poiché la query string è scritta da chi compone il link, qualsiasi richiesta REST può auto-esentarsi dal controllo nonce aggiungendo un parametro dall'aspetto innocuo contenente la stringa letterale elementor/v1/events/. Ad esempio, tutte le seguenti soddisfano il controllo mentre la richiesta viene effettivamente inviata a un endpoint completamente diverso: /wp-json/wp/v2/users?zzz=elementor/v1/events/, /wp-json/wp/v2/users?elementor/v1/events/ (nessun nome di parametro), e /wp-json/wp/v2/users?q=foo-elementor/v1/events/-bar (nemmeno un segmento intero).
Restituire true da questo filtro è più forte che saltare semplicemente un controllo. Il filtro rest_authentication_errors è un canale condiviso, e ogni gestore ben educato su di esso inizia verificando se un gestore precedente ha già preso una decisione. Il controllo nonce di WordPress core è scritto esattamente in questo modo: ritorna immediatamente se un filtro precedente ha restituito un valore non vuoto. Poiché il filtro di Elementor viene eseguito con priorità 0 e restituisce true, dichiara che l'autenticazione è già riuscita prima che chiunque altro possa intervenire. La verifica nonce di core non viene mai raggiunta, e qualsiasi plugin di sicurezza che rafforza l'autenticazione REST attraverso lo stesso filtro viene saltato insieme ad essa. Ciò che rimane è il permission_callback della route, che chiede cosa l'utente corrente è autorizzato a fare. Poiché la vittima è autenticata, il suo cookie risponde generosamente a questa domanda. L'autorizzazione regge ancora; è solo la prova dell'intento che è sparita.
La maggior parte delle scoperte di CSRF REST richiede una pagina che invii un modulo o esegua una richiesta fetch(), il che limita la consegna a luoghi dove l'attaccante può inserire script o markup. Questa no, perché WordPress core accetta un parametro di query _method che sovrascrive il verbo HTTP. Una semplice navigazione GET, come cliccare un link normale, è sufficiente per eseguire una scrittura. L'intero attacco sta in un URL: https://example.com/wp-json/wp/v2/users?_method=POST&username=csrfadmin&email=csrfadmin%40example.test&password=...&roles%5B%5D=administrator&x=elementor/v1/events/. Senza il parametro finale, la stessa richiesta restituisce rest_cannot_create_user con HTTP 401. Con esso, il server restituisce HTTP 201 e un oggetto utente il cui array roles è ["administrator"]. Il ricercatore ha confermato che un marcatore un carattere più corto del namespace reale, elementor/v1/event/, viene rifiutato, escludendo qualsiasi altra spiegazione per la differenza. Poiché basta un singolo tag anchor, il payload può essere consegnato ovunque possa andare un link: un'email, un messaggio di chat, un post su un forum, un commento su un sito non correlato. La vittima vede un link normale e una risposta JSON.
Il raggio d'azione è ogni route REST. Questa non è una vulnerabilità negli endpoint di Elementor che capita di essere raggiungibile via CSRF. Il bypass viene valutato prima del routing, quindi si applica all'intera superficie API REST del sito: le route di WordPress core e le route di ogni altro plugin installato insieme ad esso. Creare un amministratore tramite /wp/v2/users è la dimostrazione più chiara, ma il ricercatore ha anche mostrato che GET /wp-json/wp/v2/settings passa da HTTP 401 a HTTP 200 con le impostazioni del sito restituite nel corpo della risposta. Tutto ciò che l'account della vittima può raggiungere via REST è nel mirino, inclusi endpoint appartenenti a plugin che non hanno fatto nulla di male.
Elementor ha corretto la falla nella versione 4.3.2. Il codice sostitutivo legge $wp->query_vars['rest_route'] invece dell'URI grezzo. Quel valore è la route che WordPress ha effettivamente risolto, dopo la riscrittura, con la query string già separata. Non c'è più alcun testo composto dall'attaccante nel valore testato. Il confronto è anche cambiato da false !== strpos(...) a 0 === strpos(...), quindi il namespace deve apparire all'inizio della route piuttosto che da qualche parte al suo interno. Questo secondo cambiamento è critico: saltarlo avrebbe lasciato una versione più piccola dello stesso bug, perché una route come /otherplugin/v1/x/elementor/v1/events/ avrebbe ancora corrisposto. Un controllo aggiuntivo is_string() chiude un'altra porta dove rest_route poteva essere inviato come array.
La causa principale è una discrepanza tra la domanda che il codice poneva e i dati disponibili per rispondere. Il codice voleva sapere "questa richiesta è per la mia route?", ma lo chiedeva in un punto in cui WordPress non l'aveva ancora deciso, e si accontentava di una ricerca di sottostringa su una stringa controllata dal client. Due lezioni generalizzano oltre questo plugin. Primo, $_SERVER['REQUEST_URI'] è input controllato dall'attaccante, non metadati di routing; qualsiasi decisione di sicurezza basata su di esso richiede la rimozione della query string e il confronto ancorato. Secondo, rest_authentication_errors è un canale condiviso, e restituire un valore truthy non è un opt-out locale. Asserisce il successo a ogni gestore a valle, inclusa la verifica nonce di WordPress core. Un filtro che deve solo dire "nessuna opinione" dovrebbe restituire $result invariato. Patchstack raccomanda fortemente di aggiornare Elementor alla versione 4.3.2 o superiore. La tempistica è breve: il report è arrivato il 2026-09-22, Elementor ha rilasciato la versione 4.3.2 il 2026-09-24, e l'advisory pubblico è stato rilasciato il 2026-09-25. Per i proprietari di siti che non possono monitorare da soli ogni release di plugin, l'hosting WordPress gestito con backup automatici e hardening della sicurezza, come AEU Hosting, riduce i danni se un plugin vulnerabile viene sfruttato e aiuta a ripristinare rapidamente una copia pulita.