The WordPress backdoor that keeps its address book on Ethereum.
A self-healing WordPress backdoor reads its command servers from three Ethereum smart contracts, captures administrators’ passwords and plants a service worker in their browsers. We compare a September sample with the October build, and follow seven months of the contracts’ history.
In short
- A family of WordPress backdoors (the authors' own build tag is
SCV) hides inside a fake plugin with a believable name. September: "Macro Gateway Pad". October: "Byte Console Rig". - It does not keep a list of command servers. It reads the current list from three Ethereum smart contracts. The domains can change every day; the contracts stay the same. This technique is known as EtherHiding.
- On the server it rebuilds itself from up to seven places, creates a hidden administrator, forges login cookies and reports administrators to the attackers.
- In the browser it plants a service worker in the administrators' browsers, which runs whatever code the attackers send. That code can show a fake verification page with ClickFix instructions (open Terminal / Run, paste, press Enter).
- One month later the same contracts and the same call are still in use, but the build has grown from about 115 to 287 functions and learned new tricks — most importantly, it now records administrators' passwords in plain text at sign-in.
Run a WordPress site or manage sites for clients? Install the ByteMantle browser extension, open your site and its admin area, and see whether it reports a service worker, a contract read or a lure. Get the extension · How to check a site
How the chain works
- A WordPress site is compromised (often through a stolen password or a vulnerable plugin). The attackers install a "plugin" whose header looks normal: a name, an author, a licence, a "Requires PHP" line.
- The plugin asks Ethereum where to report. It calls a read-only function (selector
0x3bc5de30) on one of three contracts, through one of about twenty public Ethereum services. The answer is masked; once unmasked it holds a 16-byte key and the current command servers. - It reports to the attackers, encrypted with that key: the site, its plugins, the administrators — and, in the October build, their passwords.
- It defends itself: copies in must-use plugins, drop-ins (
advanced-cache.php,db.php), the theme,.user.ini/.htaccess(auto_prepend_file), hidden files in the cache folder, a scheduled task, and its own state hidden in the database under option names derived from the install path. Delete one copy and the others put it back. - It reaches into browsers. On the sign-in page and in the admin area it adds a short script that registers a service worker — a script the browser keeps running for the site in the background — and executes whatever Base64-encoded code that worker passes on. The attackers can then change admin pages, capture what is typed, upload plugins with the administrator's own session, or show a ClickFix lure.
What changed between September and October
| September sample | October build (SCV 5.1.2) | |
|---|---|---|
| Disguise | "Macro Gateway Pad" — "Robust health check assistant" | "Byte Console Rig" — "Modern static asset optimization extension" |
| Size | 177 KB, ~115 functions | 440 KB, 287 functions |
| Ethereum contracts / call | 3 contracts, selector 0x3bc5de30 | the same 3 contracts, the same selector |
| Service worker address | /?sc_9a42d7=1 — an unusual parameter | /?p=91xxxxxx — looks like an ordinary WordPress post link |
| Where the worker is planted | sign-in page | sign-in page and admin area, HTTPS only |
| Administrator passwords | hashes and forged cookies sent; plain-text capture not established | plain-text passwords captured at sign-in (kept up to 90 days) and sent with the report |
| Two-factor sign-in | — | counts sign-ins where the password was right but the login never completed: a sign of 2FA on that account |
| Hiding | hides its user and plugin | also switches off WordPress's e-mails about new users and new sign-ins, hides itself from file-manager plugins, hides updates |
| Cleaning attempts | self-healing | also detects a "poisoned" recovery copy (a file a cleaner replaced with blank text) and refuses to restore from it; checks the site still loads after each change and undoes the change if it broke the site (so it is not noticed); several copies agree on the newest version and retire the older ones |
The contracts' history: seven months of rotating servers, one key
Reading the contracts' public history (read-only eth_call and the Blockscout explorer, checked again on 30 October 2026) shows every change of address book since the contracts were created on 5 April 2026. Each time, the operator writes the same new list to all three contracts within about a minute:
| Written (UTC) | Command servers (defanged) | Path |
|---|---|---|
| 5 Apr – 22 Apr | one server at a time: a1-analytics[.]sbs, m1-analytics[.]top, e2-analytics[.]xyz, b2-analytics[.]xyz, a2-analytics[.]xyz | /n3s9c2a |
| 22 May, 20 Jun | mg-analytics[.]sbs, then fg-analytics[.]biz | /n3s9c2a |
| 1 Jul | great-fade[.]sbs, admiration-noble[.]sbs | /n3s9c2a |
| 4 Jul | pace-draft[.]sbs, rebel-pause[.]xyz, grant-member[.]pro | /n3s9c2a |
| 16 Jul | football-attraction[.]pro, relaxation-seed[.]xyz, bacon-rumors[.]xyz | /n3s9c2a |
| 4 Aug | siege-close[.]com, fashion-chicken[.]com, carpet-sail[.]com | /n3s9c2a |
| 19 Aug | chief-ignite[.]pro, hair-result[.]xyz, soup-tone[.]pro | /n3s9c2a |
| 20 Aug, 20:47 | chief-ignite[.]pro, seat-aviation[.]com, soup-tone[.]pro | /n3s9c2a |
| 21 Aug, 00:21 | root-cherry[.]com, forecast-chaos[.]com, sound-obstacle[.]com | /n3s9c2a |
| 4 Sep, 16:08 | basic-junior[.]com, railroad-boot[.]com, great-basic[.]com | /SGct2K |
| 8 Sep, 19:16 | castle-lid[.]com, highlight-pyramid[.]com, colon-strange[.]pro | /SGct2K |
| 9 Sep, 10:56 | notion-brown[.]com, gear-carriage[.]com, tape-exposure[.]com | /SGct2K |
| 11 Sep, 19:41 | stand-medal[.]com, truth-dialogue[.]com, cold-pyramid[.]com | /SGct2K |
| 15 Sep, 13:07 | correspondabb[.]com, rehearsal-b[.]com, chordapple[.]com | /SGct2K |
| 19 Oct, 22:11 | fruit-overall[.]com, decoyanswer[.]com, egg-crusade[.]com | /SGct2K |
| 20 Oct, 01:07 | the same three | /vImdk1k |
| 24 Oct, 13:05 (current on 30 Oct) | the same three | /4qX0LB |
- Twenty-two writes in seven months. The operator started with one "analytics"-looking server at a time on cheap top-level domains (
.sbs,.xyz,.top,.biz), moved to two and then three random word pairs in July, and to mostly.comnames from August. The servers usually change days or weeks apart; the path is changed separately. - The 16-byte server key has not changed since the contracts were created in April. Every report the backdoor sent in that time, and every stored configuration, is encrypted with the same key: a defender who has it can read captured traffic and the
sc_c2_cacheoption on an infected site.
What the service worker does in the administrator's browser
The worker that the plugin plants (October: /?p=<8 digits>) was captured from an infected site and read statically:
- It steals the WordPress sign-in. It watches the browser's requests; when the administrator submits
wp-login.php, it copies the user name and password, encrypts them with the same server key and sends them to the command server — in addition to the server-side capture. Cleaning the server does not stop this: the worker lives in the browser. - It reinstalls the backdoor from the browser. On admin pages it checks whether the plugin is still there. If it is gone, it downloads the plugin package and uploads it through WordPress's own "Upload plugin" page, using the administrator's open session. A site that was cleaned on the server is re-infected the next time an administrator opens the dashboard.
- It injects the attackers' page code into admin pages and keeps itself current (
skipWaiting,clients.claim, background sync).
So: the browser is a second place the infection lives. The server and the administrators' browsers have to be cleaned in the same window — see Cleaning.
A second, separate campaign on the same site
The home page of the same site carried two more inline loaders. They are not SC code: they read a different contract on Polygon (0x83833C5D676cA06E941A32310AE67D0890F657eE), get back a domain (at the time makeverizyjar[.]info) and load a script from it — the classic front-end EtherHiding lure loader. When the export was taken the domain no longer resolved, so visitors saw nothing; one write to the contract would bring it back. Compromised WordPress sites are often shared by several operators: cleaning must cover both.
The lesson: the authors change everything a scanner looks at — plugin name, author, file size, the worker's address — but they keep the part that is expensive to change: the contracts. That is the anchor defenders should hunt for.
How to check a WordPress site
- Search the files for
0x3bc5de30and for a header comment/* SCV:. - Look for unexpected must-use plugins,
advanced-cache.php/db.phpyou did not install,auto_prepend_filein.user.inior.htaccess, and PHP files inwp-content/cache. - In the page source of
wp-login.php, look for a<script data-sc-…>tag. - On the server, a PHP process talking to public Ethereum services is almost never legitimate.
- In
wp-config.php, look for code or a marker you did not add (the October build checks for its ownSC_WCmarker there). - In the database, look beyond the obvious: options named
sc_…and options with short random-looking names (the September build names its options from an MD5 of the install path, so a text search for its keys finds nothing), cron events you do not recognise, administrators you do not know. - File dates prove nothing: the backdoor resets the modification time of the files it writes.
Cleaning: why one step is never enough
This family is built to survive cleaning. In the code we read, it keeps several copies in different places (plugin, must-use plugins, advanced-cache.php / db.php drop-ins, the theme, wp-config.php, on sites infected by older builds also .user.ini / .htaccess via auto_prepend_file, hidden files in wp-content/cache), a recovery copy of its own source in the database, state in PHP shared memory, scheduled tasks, and checks that put any missing copy back — from a copy it trusts: it recognises a recovery copy a cleaner has blanked out and refuses it, and undoes its own changes if they break the site, so nobody notices. It copies itself to other WordPress installs it finds on the same hosting account (every ten minutes at most), fakes file dates, hides itself from the plugin list and from file-manager plugins, keeps a hidden administrator and forged login cookies, and — through the service worker — reinstalls itself from an administrator's browser.
Removing the plugin, or any one copy, only triggers the repair. Cleaning has to be planned and done from outside WordPress (SSH / SFTP, the hosting panel, the provider's tools), in this order:
- Preserve evidence first: a full copy of the files and a database dump, server logs, file hashes. Everything below destroys evidence.
- Contain: block the server's outbound traffic (command servers and public Ethereum services); take the site offline or into maintenance; no administrator signs in until the end — every dashboard visit with the worker alive can reinstall the plugin and leak the password again. Treat every other site on the same hosting account as infected until checked.
- Remove everything in one pass, with PHP stopped: every copy in the files above, the code in
wp-config.php,.user.ini/.htaccess; the database options (named and derived), cron events, transients, the hidden administrators. Where integrity cannot be proven, reinstall WordPress core, plugins and themes from clean sources instead of editing files. Then restart PHP (this also clears its code cache and shared memory). - Replace every secret: all administrator passwords, the authentication keys and salts in
wp-config.php(this voids forged cookies and all sessions), the database password, hosting / SFTP passwords and API keys stored on the site. The October build had the passwords in plain text — assume they are known. - Clean the administrators' browsers: in each browser that opened the dashboard, remove the service worker registered for this site (browser settings → site settings → this site → Clear data — this deletes what your browser stored for the site, it does not touch the website), or let ByteMantle remove it. Do it before that browser signs in again.
- Verify it does not come back: load the site and the dashboard several times, re-check the files, the database and the administrator list over the following days, watch outbound traffic for Ethereum or command-server calls. A copy that reappears means something was missed — usually another site on the same account.
If you are not sure you can do all of this, involve the hosting provider or an incident-response team. ByteMantle detects the browser side of this infection and can remove the worker from a browser; it does not clean the server.
Where a browser-side defence helps
The server part is a job for the hosting provider and the site owner. The browser part is where the people at risk are: the site's administrators and anyone who meets the ClickFix lure. ByteMantle looks at what happens in the browser, so in this chain it sees:
- a service worker registered from a page-like address (both
?sc_…=1and?p=…are page addresses, not script files); - the page reading an Ethereum contract to find its next step (EtherHiding);
- an inline loader that hides its names and talks JSON-RPC;
- a ClickFix page asking to paste a command, and the command itself when it lands in the clipboard.
Each finding reaches the organization's console with the page, the frame and the evidence, so one administrator's browser warns the whole team.
Check your site with ByteMantle
- Install the extension in the browser you use for the site's admin area: Get the extension.
- Open the site, then
wp-login.phpand the dashboard — the way you normally would. - Look at the extension's report: a service worker on the site, a page reading a smart contract, an inline loader or a ClickFix page are each shown with the address and the evidence. Nothing found is a good sign, not proof: the server part can only be checked on the server (see the steps above), and some builds hide from known visitors.
- If it finds the worker, treat the site as compromised: do not keep using the dashboard, keep the extension's findings as evidence (they show the page, the frame and the worker's address), and follow Cleaning — the server, the secrets and every administrator's browser, in the same window. Removing the worker from one browser alone fixes nothing.
- Managing many sites or a team? With the ByteMantle console, one administrator's browser warns the whole organization, and every finding arrives with the page, the frame and the evidence. See ByteMantle for teams →
Indicators (defanged)
- Ethereum contracts:
0x9A4752cAA1C15868487A0ACb691F81bfA901E063,0x839d1cE5c3F259e8d3D17114d7186EDabdbeA94b,0x6d2c5435EF70196740a48904B69377935D50abBB; selector0x3bc5de30 - Build tag
SCV:5.1.2; fake plugins "Macro Gateway Pad", "Byte Console Rig"; fake author sitesclark[.]dev,owenlewis[.]dev - Command servers (they rotate; full timeline above): current
fruit-overall[.]com,decoyanswer[.]com,egg-crusade[.]com(path/4qX0LBsince 24 Oct; earlier/vImdk1k,/SGct2K,/n3s9c2a); earlier setscorrespondabb[.]com,rehearsal-b[.]com,chordapple[.]com,stand-medal[.]com,truth-dialogue[.]com,cold-pyramid[.]com,notion-brown[.]com,gear-carriage[.]com,tape-exposure[.]com,root-cherry[.]com,forecast-chaos[.]com,sound-obstacle[.]com(/n3s9c2a),chief-ignite[.]pro,seat-aviation[.]com,soup-tone[.]pro - Database option names starting with
sc_(for examplesc_last_rpc,sc_c2_cache,sc_sw_url,sc_canary) - Front-end loader (separate campaign): Polygon contract
0x83833C5D676cA06E941A32310AE67D0890F657eE, selectorb68d1809, domainmakeverizyjar[.]info(/api.php?s=<48 hex>) - Service worker URL:
/?p=<8 digits>(October) or/?sc_xxxxxx=1(September);<script data-sc-xxxxxx>onwp-login.php
Credits and further reading
- Sucuri — SC WordPress malware: a self-healing mesh of loaders, drop-ins and a blockchain-controlled backdoor (Gabriel Barbosa, 30 September 2026)
- Monarx — The WordPress infection that rebuilds itself faster than you can delete it and Recovering from the self-healing WordPress infection
- Jump.BG — WordPress SC 4.0.3 self-healing malware (August 2026)
- drweb.ro — Site care se reinfectează după fiecare curățare, case study of an online shop (6 August 2026; in Romanian): SC 4.0.3 in the fake plugin "haven-conductor-lite" (fake author "Liam Clark"), and the same three Ethereum contracts
Stop these attacks before anything runs.
Free browser protection for everyone, in Chrome and Edge. One console for your whole company when you need it.