{"id":257,"date":"2026-08-09T10:42:59","date_gmt":"2026-08-09T08:42:59","guid":{"rendered":"https:\/\/helloblog.io\/it\/bdthemes-xss-api-compromissione-supply-chain\/"},"modified":"2026-08-09T10:42:59","modified_gmt":"2026-08-09T08:42:59","slug":"bdthemes-xss-api-compromissione-supply-chain","status":"publish","type":"post","link":"https:\/\/helloblog.io\/it\/bdthemes-xss-api-compromissione-supply-chain\/","title":{"rendered":"BdThemes: una risposta JSON avvelenata compromette i plugin WordPress"},"content":{"rendered":"\n<p>Una compromissione della supply chain ha colpito l&#8217;ecosistema di plugin BdThemes senza modificare alcun file nel repository ufficiale di WordPress.org. Gli attaccanti hanno alterato una risposta JSON remota usata per mostrare banner promozionali nella Bacheca e hanno sfruttato una XSS per eseguire JavaScript nel browser di ogni amministratore autenticato.<\/p>\n\n\n\n<p>I sette plugin coinvolti sono stati chiusi temporaneamente nella directory di WordPress durante l&#8217;ispezione. Se li hai usati, non limitarti a verificare gli aggiornamenti: controlla utenti, plugin, directory dei Must-Use plugin e tabella delle opzioni del database.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">La vulnerabilit\u00e0: una XSS nel campo <code>display_id<\/code><\/h2>\n\n\n\n<p>Biggopti \u00e8 un componente interno distribuito nei plugin BdThemes che scarica banner promozionali dall&#8217;API del fornitore e li renderizza nell&#8217;area amministrativa di WordPress. L&#8217;API legge file JSON statici da un bucket DigitalOcean Spaces protetto da Cloudflare, non da un application server dinamico.<\/p>\n\n\n\n<p>La libreria Biggopti presenta una vulnerabilit\u00e0 Cross-Site Scripting (XSS) con punteggio CVSS <strong>5,4 su 10<\/strong>, classificata come media e priva di correzione al momento della rilevazione. Il parsing insufficiente della risposta della Sigmative API consente a chi controlla quel server di iniettare script nelle pagine visualizzate dagli utenti.<\/p>\n\n\n\n<p>Ogni plugin che usa Biggopti registra un asset JavaScript client-side sull&#8217;hook <code>admin_init<\/code>. Lo script parte quindi a ogni caricamento di qualunque pagina <code>wp-admin<\/code>, recupera i dati del banner e concatena <code>display_id<\/code> nell&#8217;attributo HTML <code>id<\/code> senza eseguire l&#8217;escaping lato client.<\/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>\/\/ Il valore remoto entra direttamente nell'attributo id.\nvar f = t.display_id || t.id || &quot;default&quot;;\nvar m = &quot;bdt-admin-biggopti-api-biggopti-&quot; + f;\nA = 'id=&quot;' + m + '&quot;';\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:#6A737D\">\/\/ Il valore remoto entra direttamente nell'attributo id.<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> f <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> t.display_id <\/span><span style=\"color:#F97583\">||<\/span><span style=\"color:#E1E4E8\"> t.id <\/span><span style=\"color:#F97583\">||<\/span><span style=\"color:#9ECBFF\"> \"default\"<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> m <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#9ECBFF\"> \"bdt-admin-biggopti-api-biggopti-\"<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> f;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#79B8FF\">A<\/span><span style=\"color:#F97583\"> =<\/span><span style=\"color:#9ECBFF\"> 'id=\"'<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> m <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#9ECBFF\"> '\"'<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>Nello stesso codice, l&#8217;attributo <code>data-display-id<\/code> viene invece sottoposto a escaping: la funzione sostituisce <code>&amp;<\/code>, <code>&lt;<\/code>, <code>&gt;<\/code>, e <code>&quot;<\/code> con le rispettive entit\u00e0 HTML. Questa differenza lascia vulnerabile l&#8217;attributo <code>id<\/code>, anche se le versioni successive hanno introdotto un sanitizer basato su <code>DOMParser<\/code> per il solo campo <code>content<\/code> del banner: il sanitizer elimina tag HTML pericolosi e handler inline, ma non risolve l&#8217;iniezione in <code>id<\/code>.<\/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>function escapeHtml(value) {\n  return (value || &quot;&quot;)\n    .replace(\/&amp;\/g, &quot;&amp;amp;&quot;)\n    .replace(\/&lt;\/g, &quot;&amp;lt;&quot;)\n    .replace(\/&gt;\/g, &quot;&amp;gt;&quot;)\n    .replace(\/&quot;\/g, &quot;&amp;quot;&quot;);\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\">function<\/span><span style=\"color:#B392F0\"> escapeHtml<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#FFAB70\">value<\/span><span style=\"color:#E1E4E8\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  return<\/span><span style=\"color:#E1E4E8\"> (value <\/span><span style=\"color:#F97583\">||<\/span><span style=\"color:#9ECBFF\"> \"\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">&#x26;<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;amp;\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">&#x3C;<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;lt;\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">><\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;gt;\"<\/span><span style=\"color:#E1E4E8\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    .<\/span><span style=\"color:#B392F0\">replace<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#DBEDFF\">\"<\/span><span style=\"color:#9ECBFF\">\/<\/span><span style=\"color:#F97583\">g<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#9ECBFF\">\"&#x26;quot;\"<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>La cronologia SVN colloca l&#8217;introduzione dell&#8217;attributo non sottoposto a escaping al 1\u00b0 marzo 2026: Prime Slider 4.1.9, revisione SVN <code>r3471891<\/code>, ha poi propagato il comportamento agli altri plugin. Un soggetto non autorizzato con accesso in scrittura al bucket ha sostituito i JSON legittimi con record costruiti ad hoc.<\/p>\n\n\n\n<p>Il valore ostile chiude l&#8217;attributo <code>id<\/code> e aggiunge un handler <code>onanimationstart<\/code>. Un&#8217;animazione CSS lo attiva entro 10 millisecondi, in silenzio, quando un amministratore apre una pagina della Bacheca. Il payload visto nel campo <code>display_id<\/code> usava <code>eval(String.fromCharCode(...))<\/code> per scaricare JavaScript remoto da <code>api.sigmative.io<\/code> e impostava lo stile <code>animation:wrapperSlideInTop .01s ease-out both<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Perch\u00e9 l&#8217;attacco elude i controlli basati sui file<\/h2>\n\n\n\n<p>Per diventare vittima non serve installare un aggiornamento del plugin. Gli attaccanti non modificano i file del plugin sul disco: la compromissione arriva interamente dall&#8217;API remota e parte nel browser dell&#8217;amministratore autenticato.<\/p>\n\n\n\n<p>Di conseguenza, gli scanner che confrontano l&#8217;integrit\u00e0 dei file non trovano modifiche e un Web Application Firewall rileva con difficolt\u00e0 il flusso. Il feed promozionale, considerato attendibile dal codice del plugin, diventa il veicolo che consegna il malware.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">La catena di compromissione a pi\u00f9 stadi<\/h2>\n\n\n\n<p>L&#8217;handler iniettato sceglie script esterni in base alla disponibilit\u00e0 dell&#8217;infrastruttura degli attaccanti. La campagna impiega un payload principale, <code>w2.js<\/code>, per i plugin che interrogano <code>api-data-all-records<\/code>, e un payload alternativo, <code>x.js<\/code>, per quelli che interrogano <code>api-data-records<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Payload principale: <code>w2.js<\/code><\/h3>\n\n\n\n<p>Eseguito nella sessione dell&#8217;amministratore, <code>w2.js<\/code> completa cinque passaggi:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>Verifica del C2:<\/strong> contatta <code>ia-cdn[.]com\/fz\/c<\/code>, inviando l&#8217;origine del sito vittima per ricevere istruzioni di targeting. Interrompe l&#8217;esecuzione se il C2 risponde con lo stato <code>skip<\/code> o <code>done<\/code>.<\/li>\n\n\n<li><strong>Creazione di un amministratore non autorizzato:<\/strong> usa l&#8217;header <code>X-WP-Nonce<\/code> gi\u00e0 disponibile nella sessione amministrativa per creare un utente amministratore attraverso la REST API di WordPress; se il tentativo fallisce, passa ai normali invii dei moduli.<\/li>\n\n\n<li><strong>Installazione di una webshell:<\/strong> scarica dal C2 un archivio ZIP che imita un plugin e lo carica attraverso il modulo standard di upload dei plugin. Il falso plugin usa slug neutri come <code>wp-smart-thumbnails<\/code> e contiene la webshell <code>emer-run.php<\/code>, richiamata direttamente tramite URL.<\/li>\n\n\n<li><strong>Backdoor nei Must-Use plugin:<\/strong> l&#8217;esecuzione di <code>emer-run.php<\/code> installa due moduli persistenti nella directory dei Must-Use plugin. I campioni osservati riportano date retrodatate a settembre 2025 per confondersi con i timestamp del filesystem; i nomi dei file possono cambiare tra un&#8217;infezione e l&#8217;altra. Il primo modulo abilita un login amministrativo senza autenticazione con il parametro URL <code>?_wplogin=&lt;token&gt;<\/code> e prende di mira l&#8217;amministratore registrato da pi\u00f9 tempo. Il secondo aggancia le query del database di WordPress, nasconde gli account creati dall&#8217;elenco degli utenti amministrativi e riduce di conseguenza il conteggio totale degli utenti.<\/li>\n\n\n<li><strong>Esfiltrazione:<\/strong> invia al C2 gli esiti di tutte le fasi esecutive mediante <code>navigator.sendBeacon<\/code>.<\/li>\n\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Payload alternativo: <code>x.js<\/code><\/h3>\n\n\n\n<p><code>x.js<\/code> risulta ospitato direttamente nell&#8217;infrastruttura BdThemes. Calcola credenziali amministrative deterministiche dall&#8217;hostname del sito vittima: crea un hash a 32 bit scorrendo i caratteri dell&#8217;host, ne usa i primi sei caratteri in base36 e costruisce utente e password.<\/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>function makeCreds() {\n  var host = siteKey();\n  var hash = 0;\n  for (var i = 0; i &lt; host.length; i++) {\n    hash = ((hash &lt;&lt; 5) - hash + host.charCodeAt(i)) | 0;\n  }\n  var n = Math.abs(hash).toString(36).slice(0, 6);\n  return {\n    user: 'bd_' + n,\n    pass: 'Bd@26!' + n + 'x'\n  };\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\">function<\/span><span style=\"color:#B392F0\"> makeCreds<\/span><span style=\"color:#E1E4E8\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  var<\/span><span style=\"color:#E1E4E8\"> host <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#B392F0\"> siteKey<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  var<\/span><span style=\"color:#E1E4E8\"> hash <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  for<\/span><span style=\"color:#E1E4E8\"> (<\/span><span style=\"color:#F97583\">var<\/span><span style=\"color:#E1E4E8\"> i <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#E1E4E8\">; i <\/span><span style=\"color:#F97583\">&#x3C;<\/span><span style=\"color:#E1E4E8\"> host.<\/span><span style=\"color:#79B8FF\">length<\/span><span style=\"color:#E1E4E8\">; i<\/span><span style=\"color:#F97583\">++<\/span><span style=\"color:#E1E4E8\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    hash <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> ((hash <\/span><span style=\"color:#F97583\">&#x3C;&#x3C;<\/span><span style=\"color:#79B8FF\"> 5<\/span><span style=\"color:#E1E4E8\">) <\/span><span style=\"color:#F97583\">-<\/span><span style=\"color:#E1E4E8\"> hash <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#E1E4E8\"> host.<\/span><span style=\"color:#B392F0\">charCodeAt<\/span><span style=\"color:#E1E4E8\">(i)) <\/span><span style=\"color:#F97583\">|<\/span><span style=\"color:#79B8FF\"> 0<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  }<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  var<\/span><span style=\"color:#E1E4E8\"> n <\/span><span style=\"color:#F97583\">=<\/span><span style=\"color:#E1E4E8\"> Math.<\/span><span style=\"color:#B392F0\">abs<\/span><span style=\"color:#E1E4E8\">(hash).<\/span><span style=\"color:#B392F0\">toString<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">36<\/span><span style=\"color:#E1E4E8\">).<\/span><span style=\"color:#B392F0\">slice<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">0<\/span><span style=\"color:#E1E4E8\">, <\/span><span style=\"color:#79B8FF\">6<\/span><span style=\"color:#E1E4E8\">);<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  return<\/span><span style=\"color:#E1E4E8\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    user: <\/span><span style=\"color:#9ECBFF\">'bd_'<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> n,<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">    pass: <\/span><span style=\"color:#9ECBFF\">'Bd@26!'<\/span><span style=\"color:#F97583\"> +<\/span><span style=\"color:#E1E4E8\"> n <\/span><span style=\"color:#F97583\">+<\/span><span style=\"color:#9ECBFF\"> 'x'<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">  };<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p>L&#8217;algoritmo genera quindi username nel formato <code>bd_<\/code> seguito da sei caratteri alfanumerici e password nel formato <code>Bd@26!<\/code> seguito dallo stesso hash e dalla lettera <code>x<\/code>. Associa inoltre l&#8217;account a un indirizzo <code>@wordpress.org<\/code>. Poich\u00e9 le credenziali dipendono dall&#8217;hostname, gli attaccanti non devono conservare centralmente l&#8217;elenco dei siti compromessi e chi svolge incident response pu\u00f2 calcolarle per cercarle su un dominio sospetto.<\/p>\n\n\n\n<p>Lo script recupera <code>wp-admin\/user-new.php<\/code> nella sessione same-origin, estrae nonce e URL di logout dall&#8217;HTML, quindi invia un POST per creare l&#8217;utente con ruolo <code>administrator<\/code>. Registra l&#8217;esito &#8211; inclusi username, password, origine del sito, URL di logout e pagina corrente &#8211; verso il C2 con <code>navigator.sendBeacon<\/code>; in alternativa usa <code>fetch<\/code> con <code>mode: 'no-cors'<\/code>, <code>credentials: 'omit'<\/code> e <code>keepalive: true<\/code>. Se disponibile, salva anche un flag in <code>localStorage<\/code> per non ripetere l&#8217;operazione nello stesso browser.<\/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>\/\/ Il payload evita una seconda esecuzione nel browser gi\u00e0 marcato.\ntry {\n  if (localStorage.getItem(DONE_KEY)) return;\n} catch (e) {}\n\nmodAdmin();\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:#6A737D\">\/\/ Il payload evita una seconda esecuzione nel browser gi\u00e0 marcato.<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">try<\/span><span style=\"color:#E1E4E8\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color:#F97583\">  if<\/span><span style=\"color:#E1E4E8\"> (localStorage.<\/span><span style=\"color:#B392F0\">getItem<\/span><span style=\"color:#E1E4E8\">(<\/span><span style=\"color:#79B8FF\">DONE_KEY<\/span><span style=\"color:#E1E4E8\">)) <\/span><span style=\"color:#F97583\">return<\/span><span style=\"color:#E1E4E8\">;<\/span><\/span>\n<span class=\"line\"><span style=\"color:#E1E4E8\">} <\/span><span style=\"color:#F97583\">catch<\/span><span style=\"color:#E1E4E8\"> (e) {}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color:#B392F0\">modAdmin<\/span><span style=\"color:#E1E4E8\">();<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Plugin e indicatori di compromissione<\/h2>\n\n\n\n<p>L&#8217;elenco dei plugin interessati comprende:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/bdthemes-element-pack-lite\">Element Pack Addons for Elementor &#8211; Elementor Widgets, Elementor Templates, Elementor Addons<\/a> &#8211; slug <code>bdthemes-element-pack-lite<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/bdthemes-prime-slider-lite\">Prime Slider Addons for Elementor &#8211; Widgets, Templates &#038; Elementor Addons<\/a> &#8211; slug <code>bdthemes-prime-slider-lite<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/pixel-gallery\">Pixel Gallery Addons for Elementor &#8211; Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery<\/a> &#8211; slug <code>pixel-gallery<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/ultimate-post-kit\">Ultimate Post Kit Addons for Elementor<\/a> &#8211; slug <code>ultimate-post-kit<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/ultimate-store-kit\">Ultimate Store Kit &#8211; Addon For WooCommerce, EDD and Elementor<\/a> &#8211; slug <code>ultimate-store-kit<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/live-copy-paste\">Live Copy Paste for Elementor &#8211; Cross Domain Copy Paste &#038; Page Duplicator<\/a> &#8211; slug <code>live-copy-paste<\/code><\/li>\n\n\n<li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/wordpress-plugins\/smart-admin-assistant\">Smart Admin Assistant &#8211; Dashboard and Site Enhancements<\/a> &#8211; slug <code>smart-admin-assistant<\/code><\/li>\n\n<\/ul>\n\n\n\n<p>Cerca inoltre questi indicatori nelle connessioni in uscita, nel filesystem e nel database:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Payload principale: <code>ia-cdn[.]com\/fz\/w2.js<\/code>.<\/li>\n\n\n<li>Endpoint beacon del C2: <code>ia-cdn[.]com\/fz\/c<\/code>.<\/li>\n\n\n<li>Endpoint BdThemes che hanno distribuito JSON avvelenato, successivamente ripuliti: <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-all-records<\/code>, <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/api-data-records<\/code> e <code>api[.]sigmative[.]io\/prod\/store\/api\/biggopti\/x.js<\/code>.<\/li>\n\n\n<li>Webshell <code>emer-run.php<\/code>, MD5 <code>1024732009983dd5e54b4cf5593f04d4<\/code>.<\/li>\n\n\n<li>Backdoor di magic login nei Must-Use plugin: <code>class-wp-token-validate.php<\/code>, MD5 <code>7719cd98a35ffad2771f26d1ceab7d27<\/code>.<\/li>\n\n\n<li>Modulo stealth nei Must-Use plugin: <code>class-wp-query-9d127ff3.php<\/code> o un nome affine al pattern <code>class-wp-query-*.php<\/code>, MD5 <code>9aadc3e5c5242b273bd17c5bdc358845<\/code>.<\/li>\n\n\n<li>Modulo Must-Use plugin presentato come health check: <code>wp-cache-optimizer.php<\/code>, MD5 <code>e450ae5bc4bfc0d960dded06a76bb8e9<\/code>.<\/li>\n\n\n<li>Opzione del database <code>fz_emer_login_tokens<\/code>, che conserva i token per il magic login.<\/li>\n\n\n<li>Opzione del database <code>fz_emer_done_v1<\/code>, che indica il completamento della compromissione.<\/li>\n\n\n<li>Account con indirizzi nei domini <code>@wordpress.org<\/code> o <code>@developer.wordpress.org<\/code>.<\/li>\n\n\n<li>Username che corrispondono al pattern <code>bd_<\/code> seguito da sei caratteri alfanumerici.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Cronologia della campagna<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong>1\u00b0 marzo 2026:<\/strong> Biggopti API JS entra in Prime Slider 4.1.9, revisione SVN <code>r3471891<\/code>; <code>display_id<\/code> viene inserito nell&#8217;attributo <code>id<\/code> senza escaping e il plugin usa l&#8217;endpoint <code>api-data-records<\/code>.<\/li>\n\n\n<li><strong>10 maggio 2026:<\/strong> l&#8217;endpoint cambia in <code>api-data-all-records<\/code>; arriva il sanitizer <code>DOMParser<\/code> per il campo <code>content<\/code>, ma l&#8217;attributo <code>id<\/code> resta vulnerabile.<\/li>\n\n\n<li><strong>23 giugno 2026:<\/strong> il campo <code>start_date<\/code> nella campagna JSON avvelenata indica l&#8217;avvio dell&#8217;avviso \u201cSummer Sale\u201d; \u00e8 la prima data possibile in cui la XSS poteva essere attiva.<\/li>\n\n\n<li><strong>6 agosto 2026, 22:40 UTC:<\/strong> ultimo aggiornamento registrato per <code>api-data-records<\/code> avvelenato.<\/li>\n\n\n<li><strong>7 agosto 2026, 09:11 UTC:<\/strong> ultimo aggiornamento registrato per <code>api-data-all-records<\/code> avvelenato.<\/li>\n\n\n<li><strong>7 agosto 2026:<\/strong> l&#8217;attacco viene osservato attivamente e i plugin vengono chiusi nella directory di WordPress in attesa di revisione.<\/li>\n\n\n<li><strong>7 agosto 2026, 16:56 UTC:<\/strong> vengono acquisiti gli artefatti dell&#8217;indagine.<\/li>\n\n\n<li><strong>8 agosto 2026:<\/strong> entrambi gli endpoint API tornano a distribuire JSON pulito.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Cosa fare sui siti esposti<\/h2>\n\n\n\n<p>Il dominio C2 \u00e8 collegato agli attori gi\u00e0 associati agli attacchi alla supply chain contro Advanced Responsive Video Embedder e OptinMonster nei due mesi precedenti. L&#8217;accesso ai record JSON dannosi e a <code>x.js<\/code> nel bucket del fornitore indica una compromissione grave delle credenziali cloud o dell&#8217;infrastruttura interna di BdThemes.<\/p>\n\n\n\n<p>Esamina subito l&#8217;elenco utenti e rimuovi ogni account amministrativo non autorizzato, con particolare attenzione ai pattern <code>bd_******<\/code> e alle email indicate. Ispeziona le directory dei plugin e dei Must-Use plugin per i file e gli hash elencati; verifica poi <code>wp_options<\/code> per <code>fz_emer_login_tokens<\/code> e <code>fz_emer_done_v1<\/code>. Dato che l&#8217;attacco pu\u00f2 aver installato una webshell e moduli persistenti, tratta ogni indicatore trovato come una compromissione completa del sito con esecuzione di codice remoto.<\/p>\n\n\n\n<p>Dopo la bonifica, ruota le credenziali amministrative e quelle dell&#8217;hosting, verifica le connessioni in uscita verso gli indicatori elencati e riesamina i plugin BdThemes prima di riattivarli. Il JSON pulito distribuito dagli endpoint non rimuove gli account, le webshell o le backdoor che un payload gi\u00e0 eseguito pu\u00f2 aver lasciato nel sito.<\/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\/08\/psa-supply-chain-compromise-in-bdthemes-ecosystem-via-poisoned-api-response\/\" target=\"_blank\" rel=\"noopener noreferrer\">PSA: Supply Chain Compromise in BdThemes Ecosystem via Poisoned API Response<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/threat-intel\/vulnerabilities\/id\/7bf1d6f9-afe2-41c2-968b-20dbc474cd73\" target=\"_blank\" rel=\"noopener noreferrer\">Biggopti Library (Various Versions) &#8211; Cross-Site Scripting via display_id from Sigmative API<\/a><\/li><li><a href=\"https:\/\/www.wordfence.com\/blog\/2026\/07\/wordfence-prism-detected-backdoored-wordpress-plugin-within-two-hours-of-it-being-introduced\/\" target=\"_blank\" rel=\"noopener noreferrer\">Wordfence Prism Detected Backdoored WordPress Plugin Within Two Hours of It Being Introduced<\/a><\/li><li><a href=\"https:\/\/optinmonster.com\/security-incident-tampered-script-served-via-optinmonster-and-trustpulse\/#what-to-check-and-do\" target=\"_blank\" rel=\"noopener noreferrer\">Security Incident: Tampered Script Served via OptinMonster and TrustPulse<\/a><\/li><\/ul>\n            <\/div>","protected":false},"excerpt":{"rendered":"<p>Un banner promozionale remoto ha aperto una XSS nei plugin BdThemes e ha trasformato ogni accesso a `wp-admin` in una possibile compromissione. Ecco come funziona la catena e quali indicatori cercare.<\/p>\n","protected":false},"author":19,"featured_media":256,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[12,11,132,10,123],"class_list":["post-257","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-sicurezza","tag-plugin","tag-sicurezza","tag-supply-chain","tag-wordpress","tag-xss"],"_links":{"self":[{"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/posts\/257","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=257"}],"version-history":[{"count":0,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/posts\/257\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/media\/256"}],"wp:attachment":[{"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/media?parent=257"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/categories?post=257"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/helloblog.io\/it\/wp-json\/wp\/v2\/tags?post=257"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}