{"id":154,"date":"2026-01-19T00:00:00","date_gmt":"2026-01-18T23:00:00","guid":{"rendered":"https:\/\/helloblog.io\/it\/cve-2025-14533-acf-extended-escalation-privilegi-senza-login\/"},"modified":"2026-01-19T00:00:00","modified_gmt":"2026-01-18T23:00:00","slug":"cve-2025-14533-acf-extended-escalation-privilegi-senza-login","status":"publish","type":"post","link":"https:\/\/helloblog.io\/it\/cve-2025-14533-acf-extended-escalation-privilegi-senza-login\/","title":{"rendered":"CVE-2025-14533 in ACF Extended: escalation dei privilegi senza login (e come mettere in sicurezza i form)"},"content":{"rendered":"\n<p>Nel mondo WordPress le vulnerabilit\u00e0 che portano a <em>privilege escalation<\/em> (escalation dei privilegi) sono tra le pi\u00f9 pericolose: se un attaccante riesce a trasformarsi in amministratore, il sito \u00e8 sostanzialmente compromesso. A gennaio 2026 Wordfence ha pubblicato un advisory su una falla critica in <strong>Advanced Custom Fields: Extended<\/strong> (slug: <code>acf-extended<\/code>), add-on molto diffuso per ACF, con oltre <strong>100.000 installazioni attive<\/strong>.<\/p>\n\n\n\n<p>La vulnerabilit\u00e0 \u00e8 identificata come <strong>CVE-2025-14533<\/strong> (CVSS <strong>9.8<\/strong>, Critical) e riguarda le versioni <strong>fino alla 0.9.2.1<\/strong>. Il fix \u00e8 stato rilasciato nella <strong>0.9.2.2<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cosa succede: da visitatore anonimo a \u201cadministrator\u201d<\/h2>\n\n\n\n<p>Il problema nasce dal modo in cui ACF Extended gestisce alcune azioni del suo <strong>form manager<\/strong> (la parte che permette di creare form e associarli ad \u201cazioni\u201d come creare\/aggiornare un utente). In particolare, l\u2019azione di tipo <strong>Create user<\/strong> (e anche Update user) usa una routine che costruisce gli argomenti per <code>wp_insert_user()<\/code> partendo dai campi del form.<\/p>\n\n\n\n<p>Nelle versioni vulnerabili, la funzione che prepara i dati non applica in modo efficace una restrizione sui ruoli consentiti. Risultato: se nel mapping dei campi finisce anche un campo <code>role<\/code>, un attaccante pu\u00f2 inviare manualmente <code>administrator<\/code> come valore e ottenere un account con privilegi amministrativi.<\/p>\n\n\n\n<div class=\"wp-block-group callout callout-warning is-style-warning is-layout-flow wp-block-group-is-layout-flow\" style=\"border-width:1px;border-radius:8px;padding-top:1rem;padding-right:1.5rem;padding-bottom:1rem;padding-left:1.5rem\">\n\n<h4 class=\"wp-block-heading callout-title\">Condizione chiave per l\u2019exploit<\/h4>\n\n\n<p>Secondo l\u2019analisi di Wordfence, l\u2019exploit \u00e8 possibile <strong>solo se il campo \u201crole\u201d \u00e8 mappato<\/strong> (cio\u00e8 collegato) a un custom field nel form di creazione\/aggiornamento utente. Senza quel mapping, la criticit\u00e0 \u201creale\u201d per il tuo sito cambia drasticamente.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Impatto pratico: perch\u00e9 \u00e8 una compromissione completa<\/h2>\n\n\n\n<p>Quando un attaccante ottiene accesso da amministratore, non si limita a \u201cvedere\u201d il backend: pu\u00f2 installare plugin e temi, caricare file (anche ZIP malevoli), modificare contenuti per fare redirect, iniettare spam o inserire backdoor. In termini operativi, \u00e8 l\u2019equivalente di consegnare le chiavi del sito.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Dettagli tecnici: dov\u2019\u00e8 il buco<\/h2>\n\n\n\n<p>Wordfence descrive la causa come una mancata restrizione dei ruoli all\u2019interno della funzione <code>insert_user()<\/code> usata dal modulo che gestisce le azioni utente nei form. In sostanza, l\u2019array di argomenti passato a <code>wp_insert_user()<\/code> pu\u00f2 includere un ruolo arbitrario, se l\u2019input arriva dal form.<\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#24292e\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" style=\"color:#e1e4e8;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><pre class=\"code-block-pro-copy-button-pre\" aria-hidden=\"true\"><textarea class=\"code-block-pro-copy-button-textarea\" tabindex=\"-1\" aria-hidden=\"true\" readonly>&lt;?php\n\/\/ Esempio concettuale (non \u00e8 il codice completo del plugin):\n\/\/ i valori arrivano dal form e vengono assemblati in $args\n$args = [];\nforeach ($save as $user_field =&gt; $value) {\n    if (in_array($user_field, $this-&gt;fields) &amp;&amp; !acf_is_empty($value)) {\n        $args[$user_field] = $value;\n    }\n}\n\n\/\/ ... poi:\n$user_id = wp_insert_user($args);\n\n<\/textarea><\/pre><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2\"><\/path><\/svg><\/span><pre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#F97583\">&#x3C;?<\/span><span style=\"color:#79B8FF\">php<\/span><\/span>\n<span class=\"line\"><span style=\"color:#6A737D\">\/\/ Esempio concettuale (non \u00e8 il codice completo del plugin):<\/span><\/span>\n<span class=\"line\"><span style=\"color:#6A737D\">\/\/ i valori arrivano dal form e vengono assemblati in $args<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">$args <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> [];<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">foreach<\/span><span style=\"color:#E1E4E8\"> ($save <\/span><span style=\"color:#F97583\">as<\/span><span style=\"color:#E1E4E8\"> $user_field <\/span><span style=\"color:#F97583\">=><\/span><span style=\"color:#E1E4E8\"> $value) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">    if<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#79B8FF\">in_array<\/span><span style=\"color:#E1E4E8\">($user_field, <\/span><span style=\"color:#79B8FF\">$this<\/span><span style=\"color:#F97583\">-><\/span><span style=\"color:#E1E4E8\">fields) <\/span><span style=\"color:#F97583\">&#x26;&#x26;<\/span><span style=\"color:#F97583\"> !<\/span><span style=\"color:#B392F0\">acf_is_empty<\/span><span style=\"color:#E1E4E8\">($value)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">        $args[$user_field] <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> $value;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#6A737D\">\/\/ ... poi:<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">$user_id <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#B392F0\"> wp_insert_user<\/span><span style=\"color:#E1E4E8\">($args);<\/span><\/span>\n<span class=\"line\"><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Il punto non \u00e8 <code>wp_insert_user()<\/code> in s\u00e9: \u00e8 il fatto che <strong>chi prepara <code>$args<\/code><\/strong> deve filtrare\/validare con estrema attenzione campi sensibili come <code>role<\/code>. Se il form \u00e8 pubblico, quel campo diventa un vettore di attacco ovvio.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Perch\u00e9 questa falla pu\u00f2 sfuggire anche a chi configura bene i campi<\/h2>\n\n\n\n<p>ACF Extended permette di definire un gruppo di campi per dati utente (email, username, password, role, ecc.) e, lato UI, offre opzioni di restrizione del ruolo (es. \u201cAllow User Role\u201d). L\u2019aspettativa naturale \u00e8 che la stessa restrizione venga rispettata quando i campi vengono usati in un form pubblico.<\/p>\n\n\n\n<p>Nelle versioni vulnerabili, per\u00f2, questa \u201cpromessa\u201d non regge: la restrizione configurata nel field group non impedisce a un attaccante di inviare un valore di ruolo diverso, se il campo ruolo \u00e8 presente\/mappato nel form.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1600\" src=\"https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1.png\" alt=\"Schermata di ACF Extended che mostra un campo ruolo con opzioni di restrizione\" class=\"wp-image-152\" srcset=\"https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1.png 2560w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1-300x188.png 300w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1-1024x640.png 1024w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1-768x480.png 768w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1-1536x960.png 1536w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1-2048x1280.png 2048w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-1-scaled-1-400x250.png 400w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><figcaption class=\"wp-element-caption\">Esempio di configurazione di un campo \u201crole\u201d con restrizioni lato UI. \u2014 <em>Forr\u00e1s: Wordfence.com<\/em><\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1599\" src=\"https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1.png\" alt=\"Schermata del form manager di ACF Extended con azione di creazione utente e mapping dei campi\" class=\"wp-image-153\" srcset=\"https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1.png 2560w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1-300x187.png 300w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1-1024x640.png 1024w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1-768x480.png 768w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1-1536x959.png 1536w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1-2048x1279.png 2048w, https:\/\/helloblog.io\/app\/uploads\/sites\/6\/2026\/01\/acfe-2-scaled-1-400x250.png 400w\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" \/><figcaption class=\"wp-element-caption\">Creazione di un form con azione \u201cCreate user\u201d e mapping dei campi. \u2014 <em>Forr\u00e1s: Wordfence.com<\/em><\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Chi \u00e8 davvero esposto (e chi no)<\/h2>\n\n\n\n<p>Non tutti i siti con <code>acf-extended<\/code> installato sono automaticamente vulnerabili in modo sfruttabile. L\u2019advisory sottolinea un dettaglio importante: la falla ha un impatto critico soprattutto sui siti che hanno configurato un form ACF Extended con azione <strong>Create user<\/strong> o <strong>Update user<\/strong> e che includono (e mappano) un campo <strong>role<\/strong>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Se usi ACF Extended solo per campi extra e non hai form pubblici che creano\/aggiornano utenti, il rischio pratico si riduce.<\/li>\n\n\n<li>Se hai un form di registrazione costruito con ACF Extended e nel mapping c\u2019\u00e8 <code>role<\/code>, sei nella casistica pi\u00f9 a rischio.<\/li>\n\n\n<li>Se il form \u00e8 accessibile da non autenticati (guest), la superficie d\u2019attacco \u00e8 maggiore.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Mitigazione: cosa fare subito (in ordine di priorit\u00e0)<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Aggiorna <strong>Advanced Custom Fields: Extended<\/strong> alla versione <strong>0.9.2.2<\/strong> o superiore (\u00e8 la versione indicata come patchata nell\u2019advisory).<\/li>\n\n\n<li>Cerca nel tuo progetto eventuali form ACF Extended con azione <strong>Create user<\/strong> \/ <strong>Update user<\/strong> e verifica se tra i campi mappati esiste <code>role<\/code>.<\/li>\n\n\n<li>Se non ti serve davvero, rimuovi il campo ruolo dal form pubblico (in generale, \u00e8 un campo che raramente dovrebbe essere controllabile dall\u2019utente finale).<\/li>\n\n\n<li>Se ti serve gestire ruoli in modo controllato, valuta un approccio server-side: ruolo assegnato da logica applicativa, non da input del browser.<\/li>\n\n\n<li>Controlla gli account admin esistenti: se vedi amministratori inattesi, ruota password, chiavi e valuta una bonifica completa.<\/li>\n\n<\/ol>\n\n\n\n<div class=\"wp-block-group callout callout-info is-style-info is-layout-flow wp-block-group-is-layout-flow\" style=\"border-width:1px;border-radius:8px;padding-top:1rem;padding-right:1.5rem;padding-bottom:1rem;padding-left:1.5rem\">\n\n<h4 class=\"wp-block-heading callout-title\">Protezione \u201ca livello firewall\u201d<\/h4>\n\n\n<p>Wordfence indica di aver distribuito una regola firewall per bloccare tentativi di exploit: agli utenti Premium\/Care\/Response l\u201911 dicembre 2025 e agli utenti Free il 10 gennaio 2026. \u00c8 una mitigazione utile, ma non sostituisce l\u2019aggiornamento del plugin.<\/p>\n\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Timeline della disclosure (per capire la finestra di rischio)<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>10 dicembre 2025: segnalazione della vulnerabilit\u00e0 tramite Bug Bounty Program di Wordfence.<\/li>\n\n\n<li>11 dicembre 2025: validazione e conferma del proof-of-concept; invio dettagli al vendor tramite Wordfence Vulnerability Management Portal; regola firewall per clienti Premium\/Care\/Response.<\/li>\n\n\n<li>14 dicembre 2025: rilascio della versione patchata <strong>0.9.2.2<\/strong>.<\/li>\n\n\n<li>10 gennaio 2026: regola firewall resa disponibile anche agli utenti Wordfence Free.<\/li>\n\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusione: la lezione per chi costruisce form \u201cintelligenti\u201d<\/h2>\n\n\n\n<p>Questo caso \u00e8 un promemoria molto concreto: quando un plugin ti permette di \u201cmappare campi\u201d verso azioni sensibili (creazione utenti, aggiornamento profili, assegnazione ruoli), l\u2019UI non basta. Anche se una schermata dice \u201cAllow User Role\u201d, la sicurezza vera \u00e8 nel codice che valida l\u2019input e nel principio del <em>least privilege<\/em>.<\/p>\n\n\n\n<p>Se nel tuo stack c\u2019\u00e8 ACF Extended, l\u2019azione pi\u00f9 pragmatica \u00e8 semplice: <strong>aggiornare alla 0.9.2.2<\/strong> e verificare rapidamente la presenza di un mapping del campo ruolo nei form esposti al pubblico.<\/p>\n\n\n<div class=\"references-section\">\n                <h2>Riferimenti \/ Fonti<\/h2>\n                <ul class=\"references-list\"><li><a href=\"https:\/\/www.wordfence.com\/blog\/2026\/01\/100000-wordpress-sites-affected-by-privilege-escalation-vulnerability-in-advanced-custom-fields-extended-wordpress-plugin\/\" target=\"_blank\" rel=\"noopener noreferrer\">100,000 WordPress Sites Affected by Privilege Escalation Vulnerability in Advanced Custom Fields: Extended WordPress Plugin<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/acf-extended\/advanced-custom-fields-extended-0921-unauthenticated-privilege-escalation-via-insert-user-form-action\" target=\"_blank\" rel=\"noopener noreferrer\">Advanced Custom Fields: Extended &lt;= 0.9.2.1 &#8212; Unauthenticated Privilege Escalation via Insert User Form Action<\/a><\/li><li><a href=\"https:\/\/www.cve.org\/CVERecord?id=CVE-2025-14533\" target=\"_blank\" rel=\"noopener noreferrer\">CVE-2025-14533<\/a><\/li><li><a href=\"https:\/\/wordpress.org\/plugins\/acf-extended\/\" target=\"_blank\" rel=\"noopener noreferrer\">Advanced Custom Fields: Extended<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/bug-bounty-program\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Bug Bounty Program<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vendor\/vulnerability-management-portal\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Vulnerability Management Portal<\/a><\/li><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>Una vulnerabilit\u00e0 critica in Advanced Custom Fields: Extended permette, in specifiche configurazioni, di ottenere privilegi da amministratore senza autenticazione. La patch esiste: il punto \u00e8 capire se il tuo sito \u00e8 davvero esposto e cosa controllare subito.<\/p>\n","protected":false},"author":19,"featured_media":151,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[75,12,11,15,10],"class_list":["post-154","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sicurezza","tag-acf","tag-plugin","tag-sicurezza","tag-wordfence","tag-wordpress"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/posts\/154","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/users\/19"}],"replies":[{"embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/comments?post=154"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/posts\/154\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/media\/151"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/media?parent=154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/categories?post=154"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/tags?post=154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}