Task-specific Atlas Agents investigate threats at machine speed with full transparency, expert validation, and explainable outcomes you can trust.
Atlas Extended Detection and ResponseOpen XDR with Agentic AI & machine learning that eliminates noise, enables real-time detection and response, and automatically blocks threats.
Atlas User ExperienceSee what our SOC sees, review investigations, and see how we are protecting your business.
Atlas Platform IntegrationsSeamless integrations and threat investigation that adapts to your tools and evolves with your business.
24/7 SOC-as-a-Service with unlimited threat hunting and incident handling.
Threat Response Unit (TRU)Proactive threat intelligence, original threat research and a world-class team of seasoned industry veterans.
Cyber Resilience TeamExtend your team capabilities and prevent business disruption with expertise from eSentire.
Response and RemediationWe balance automated blocks with rapid human-led investigations to manage threats.
Combine AI-driven security operations, multi-signal attack surface coverage and 24/7 Elite Threat Hunters to help you take your security program to the next level.
Get unlimited Incident Response with threat suppression guarantee - anytime, anywhere.
CTEM and advisory programs that identify security gaps and build proactive strategies to address them.
Flexible MDR pricing and packages that fit your unique security requirements.
Entry level foundational MDR coverage
Comprehensive Next Level eSentire MDR
Next Level eSentire MDR with Cyber Risk Advisors to continuously advance your security program
Stop ransomware before it spreads.
Identity ResponseStop identity-based cyberattacks.
Zero Day AttacksDetect and respond to zero-day exploits.
Cybersecurity ComplianceMeet regulatory compliance mandates.
Third-Party RiskDefend third-party and supply chain risk.
Cloud MisconfigurationEnd misconfigurations and policy violations.
Cyber RiskAdopt a risk-based security approach.
Mid-Market SecurityMid-market security essentials to prioritize.
Sensitive Data SecurityProtect your most sensitive data.
Cyber InsuranceMeet insurability requirements with MDR.
Cyber Threat IntelligenceOperationalize cyber threat intelligence.
Security LeadershipBuild a proven security program.
On March 4th, 2026, Cisco disclosed two maximum severity vulnerabilities impacting Cisco Secure Firewall Management Center (FMC) Software. Identified as CVE-2026-20079 (CVSS: 10.0) and…
On February 28th, 2026, the United States and Israel conducted major attacks against Iran, dubbed Operation Epic Fury and Operation Roaring Lion. Attacks against Iran will likely result in…
eSentire is The Authority in Managed Detection and Response Services, protecting the critical data and applications of 2000+ organizations in 80+ countries from known and unknown cyber threats. Founded in 2001, the company’s mission is to hunt, investigate and stop cyber threats before they become business disrupting events.
About Us Leadership Careers Event Calendar → Newsroom → Aston Villa Football Club →We provide sophisticated cybersecurity solutions for Managed Security Service Providers (MSSPs), Managed Service Providers (MSPs), and Value-Added Resellers (VARs). Find out why you should partner with eSentire, the Authority in Managed Detection and Response, today.
Search our site
Multi-Signal MDR with 300+ technology integrations to support your existing investments.
24/7 SOC-as-a-Service with unlimited threat hunting and incident handling.
We offer three flexible MDR pricing packages that can be customized to your unique needs.
The latest security advisories, blogs, reports, industry publications and webinars published by TRU.
Compare eSentire to other Managed Detection and Response vendors to see how we stack up against the competition.
See why 2000+ organizations globally have chosen eSentire for their MDR Solution.
In February 2026, eSentire's Threat Response Unit (TRU) detected DEV#POPPER, a sophisticated Remote Access Trojan (RAT), on a customer's machine in the Energy, Utilities, and Waste industry. TRU attributes this threat with high confidence to a North Korean state-sponsored APT group due to shared Tactics, Techniques, and Procedures (TTPs) across similar campaigns, such as Ransom-ISAC's blog, "Cross-Chain TxDataHiding Crypto Heist: A Very Chainful Process (Part 2)".
TRU assesses this group is primarily financially motivated, as the malware aggressively targets cryptocurrency wallets. However, targeting developers through fake GitHub repositories reveals additional objectives: supply chain compromise by stealing source code credentials, API keys, passwords, and cloud infrastructure access tokens.
This technical analysis serves two primary objectives:
Initial access occurred when the victim cloned a repository from GitHub named, "ShoeVista" - a weaponized GitHub repository disguised as an eCommerce platform. Launching the frontend application triggered a hidden malicious script that progressed through several stages before leveraging multiple blockchain networks to retrieve the source code for DEV#POPPER RAT, and stagers leading to OmniStealer (a Python-based information stealer).
While TRU has found that most victims use macOS, the malware also supports Windows and Linux, underscoring the APT’s broad targeting strategy and enabling it to compromise a wider range of systems.
The attack chain begins when the victim clones the malicious repository and opens the frontend application. Doing so triggers a sequence of stagers that ultimately deploy DEV#POPPER RAT and OmniStealer. DEV#POPPER’s source code is retrieved from blockchain transaction input data, decrypted, and then executed.
Initial access began after the victim cloned the ShoeVista GitHub repository, launched the application frontend and navigated to the frontend address in a web browser. This action launched a highly obfuscated Node.js-based backdoor in the file at "frontend/tailwind.config.js".
The last line in this file begins with a large amount of whitespace to hide highly obfuscated code.
Removing the whitespace reveals the first stage in the attack chain - highly obfuscated JavaScript that we will refer to as Stage 1. This JavaScript is executed in a new node process as an inline expression, e.g. "node -e <JavaScript>".
After beautifying the code, we can see that it serves to unpack and execute another stage. It does so by calling the function "gOe" several times, which un-shuffles two strings. The first is the string 'constructor', the second, is code that serves to decrypt the next stage.
It overwrites the gOe function with the next stage decryption code and calls it to decrypt the next stage (Stage 2). The format of this stage is very similar to Stage 4 and unpacks itself using the same functionality.
Deobfuscating this stage reveals that it serves to send an HTTP request to 23.27.20[.]143 (ASN 149440 - Evoxt Sdn. Bhd.), decrypt the response via XOR key "ThZG+0jfXE6VAGOJ", and execute the decrypted result as code via the eval() function.
The User-Agent header value is set to, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/131.0.0.0 Safari/537.36" in the request. It also sets a custom header, "Sec-V" to a value previously stored in the global variable "_V". This global variable is set by the prior stage and varies between campaigns.
The following python code emulates the behavior of the second stage: sending the request with specific headers and decrypting the response via XOR key "ThZG+0jfXE6VAGOJ". This code can be used to retrieve the third stage (DEV#POPPER).
The third stage serves three primary functions: evasion in analysis environments, and to load DEV#POPPER RAT and Omni Stealer. It is around 2,000 lines of highly obfuscated JavaScript that makes use of several anti-analysis techniques to hinder reverse engineers and automated deobfuscators. Deobfuscating and cleaning up the code reveals the original code is around 400 lines. Obfuscation of this stage is identical to Stage 5 (the DEV#POPPER RAT itself).
This section describes in-depth, the various JavaScript obfuscation techniques employed by DEV#POPPER variants.
Strings are RC4-encrypted, base64-encoded, and stored in a shuffled array. During execution, the array is reordered and indices are stored throughout the code to serve as lookups into this array. The indices are primarily stored as property values, e.g. "a0e6.l" or numeric literals, e.g. "0x55a".
The unshuffling function is seen in the figure below. It is an IIFE function (Immediately Invoked Function Expression) that takes two parameters, the encoded strings array returned by the "a0c" function, and the shuffle egg, "0x52d72" which is used to determine when the encoded strings array has been re-ordered successfully.
Each iteration of the loop compares against the egg, if it is not found, the first string of the encoded strings array is moved to the end of the array and the process repeats until the egg has been found, indicating the array has been re-ordered successfully.
The final index needed to acquire the original encoded string is obtained by subtracting the index passed to the decrypt function (a0d) from 0x151. Each string is decoded via base64 by the "g" function using the custom alphabet: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=.
Decoded strings are decrypted via RC4 using 4-byte keys that are stored throughout the code as either:
The function "k" is responsible for calling the "g" function to decode the base64-encoded string and RC4 decrypt the result.
As a simple obfuscation method, some strings use the escape sequence \x. The figure below shows two obfuscated strings, along with comments indicating their decoded ASCII characters (regular expression patterns). These are used for anti-analysis purposes, which we will describe more in-depth in the next section.
As an additional obfuscation method, string decryption calls are "proxied" and eventually call the core base64 decode + RC4 decryption routine (a0d). The order in which arguments are passed varies in the proxy chains - sometimes the RC4 key string is passed as the first argument and the index second, or vice versa.
Many strings are accessed via property name, e.g. "o[aX('m)7Q', 0x734)]", complicating replacement of the original expression with the string literal. The property value itself is also a call expression, where the callee is a "proxy" function that eventually calls the core decryption routine "a0d".
Strings (post-decryption) are sometimes separated by the "+" operator, e.g. "abc" + "def", and are concatenated at runtime.
Object-method calls are used to obfuscate both binary and call expressions. The method name is not referenced directly, rather it is computed at runtime by calling a proxy function, which ultimately invokes the string decryption routine (a0b) and returns the decrypted property name (e.g., "Qccdx"). That property is then used to index into an object (e.g., o), which contains the corresponding function implementation.
Invoking o[decryptedPropertyName]() executes the underlying behavior - either performing the original binary operation or forwarding to the intended call expression.
Bracket Notation is used throughout to hinder IDE formatting of well-known function names, e.g. "a['startsWith']()" rather than "a.startsWith()".
eSentire TRU has created a script, available here, for deobfuscating DEV#POPPER intermediary stagers and final payloads like DEV#POPPER RAT. The script traverses the Abstract Syntax Tree (AST) produced by the Babel parser and processes it through the following steps, in order:
TRU discovered several anti-analysis methods while analyzing DEV#POPPER.
The first anti-analysis method causes the Node.js debugger to crash with Type Error exceptions when the code is in its original "minified" state, making beautification the only viable option for debugging.
The second method is a self-integrity check that uses a regular expression to identify changes in the code of a function defined in the property at "this['aLQvHN']". If the code is beautified, this regular expression will match, and the for loop will execute indefinitely. The regular expression used by this technique is: "\w+ *() *{\w+ * ['|"].+['|"];? *}".
The third anti-analysis method makes use of the regular expression "(((.+)+)+)+$" and causes catastrophic backtracking by converting the a0a function to string and matching and converting the a0a function's constructor to string and searching. This causes the debugger to get hung up indefinitely.
On Windows systems, the malware enumerates running processes via tasklist /FO CSV /NH and calculates MD5 hashes of process names starting with the letter "O". If a process hash matches the MD5, "9a47bb48b7b8ca41fc138fd3372e8cc0", execution terminates. The specific process name corresponding to this hash has not been identified.
If the operating system is Linux, the next method checks various attributes about the infected machine: computer name, username, and OS release information to determine if it is likely running in an analysis environment.
Environments it avoids:
Otherwise, if the operating system is not Linux, the victim's computer is checked against the following names, which are likely controlled by the threat actors and are used for testing purposes:
The figure below displays the request sent by Stage 2 to retrieve DEV#POPPER. The response body is XOR encrypted as we previously covered.
Three different C2 addresses were identified in DEV#POPPER samples and the usage of one over another depends on the value stored in the global variable, "_V", which serves as a campaign identifier. As seen in Figure 4, the variable is set in this case to "5" so the C2 chosen is "198.105.127[.]210".
Note, this is the same global variable used for the Sec-V header that we previously covered.
DEV#POPPER filters "noisy" environment variables before sending the remaining variables to its C2.
The figure below displays the request DEV#POPPER sends to the C2 endpoint at /snv containing harvested environment variables. Since developers frequently store sensitive credentials in environment variables, this data is highly valuable.
DEV#POPPER sends a request to the C2's /$/z1 endpoint to retrieve the base64 encoded + XOR encrypted OmniStealer payload. Keep in mind this request originates from the python process started by DEV#POPPER and is invoked in memory via python's exec() function. This is covered more in-depth in the next section.
Loading DEV#POPPER RAT involves execution of an additional stage "Stage 4" that is near identical in obfuscation to Stage 1 (see Figure 4) so we will not cover it in-depth, however its purpose is to retrieve and deobfuscate the DEV#POPPER RAT JavaScript code from a chain of crypto addresses.
After deobfuscating Stage 4, we can see that it calls the function "t" and passes an XOR key, Tron address, and Aptos address (as a fallback option). After the function returns, it executes it via the eval function, effectively finding/deobfuscating/decrypting the DEV#POPPER RAT source-code from across crypto networks (Tron -> Ethereum).
The "t" function that we discussed previously can be seen in the figure below. The purpose of the first request shown is to acquire the Ethereum address in the response data via Trongrid or Aptos as a fallback, which is hex encoded.
The next figure shows the raw response data returned by Trongrid. When the hex-encoded content is decoded, it reveals the Ethereum transaction address 0x804b000af7d7e4337ba5db28bb367da64a08391de09ffb07847ac897c5f82954. This same address was also cited by Ransom-ISAC in their October 27, 2025 blog post, "Cross-Chain TxDataHiding Crypto Heist: A Very Chainful Process (Part 2)", underscoring that data stored via crypto-networks is effectively permanent.
Next, a POST request is sent to bsc-dataseed.binance.org (Binance Smart Chain) or bsc-rpc.publicnode.com (PublicNode) as a fallback option. The response data is deobfuscated and decrypted via XOR key, "cA]2!+37v,-szeU}", where it is returned and executed via eval as we previously discussed.
For clarification purposes, the next figure displays the hex-encoded source code for DEV#POPPER RAT stored in the Ethereum blockchain:
The next figure simulates the same behavior but in CyberChef, decoding from UTF-8, splitting by the string, "?.?", and decrypting via XOR, revealing Stage 5 (DEV#POPPER RAT).
Loading Omni Stealer involves first downloading a portable python zip archive from the C2 and extracting it via tar or as a fallback, via 7-Zip. This is followed up by execution of an inline python expression via python -c to execute the stager code that downloads/decrypts another stage that ultimately deploys OmniStealer, a python-based information stealer.
After beautifying the stager code, we can see that it sends a request to the C2, decrypts the response via XOR key, "9KyASt+7D0mjPHFY", and executes the decrypted result via python's exec() function.
It uses the same user agent as the stager that acquires DEV#POPPER, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML; like Gecko) Chrome/131.0.0.0 Safari/537.36".
The following CyberChef recipe can be used to decrypt a response captured from the C2 for this stage:
The next stage serves to execute the final stage (OmniStealer) through the following steps:
The following CyberChef recipe can be used to emulate this behavior and decrypt the final stage:
Deobfuscating the RAT is a simple task using the tool we previously mentioned in this blog. The RAT establishes persistent C2 communications via the NPM package socket.io-client , where it listens for commands from the C2 and sets up persistence by injecting code into several applications that make use of Node.js.
The following table lists commands supported by the RAT and associated description.
The victim's clipboard is captured by running various commands depending on the victim host OS:
DEV#POPPER RAT appends JavaScript code of the prior stage we discussed (Stage 4) at the end of JavaScript files belonging to many different applications that internally make use of Node.js including, Visual Studio Code, GitHub Desktop, Discord, Cursor, and Antigravity.
When one of those applications start, the stager code executes - DEV#POPPER RAT source code is retrieved in the same manor as previously described and executed in memory. The RAT hard-codes paths for compatibility across Windows, Linux, and macOS.
It is possible that the threat actors used an LLM to generate the source code for the RAT, given the extensive use of emojis, or that they prefer to see emojis prepended to debug messages sent to their C2 backend.
OmniStealer is around 1,000 lines of python code and targets the following:
The malware installs the following dependencies via pip:
The following table lists cryptocurrency wallets targeted by the stealer.
All harvested data is written to a password protected zip archive and exfiltrated to the C2 over HTTP. The password used in encrypting the archive is: ",./,./,./". The figure below displays the contents of a sample zip archive. On the surface, we can immediately see that the victim's login keychain database was stolen.
The _info.json file contains a JSON formatted list of information about the victim system, campaign ID, hardware ID, user ID, timestamp, etc.
As a fallback option, exfiltration occurs via Telegram via chat/group IDs: 7699029999, 7609033774, and -4697384025.
The following Censys query can be used to identify additional C2s:
The following Yara rule can be used to detect the initial stager for DEV#POPPER. The remainder of stages discussed herein are only resident in memory.
The Node.js script DEV#STOPPER.js is available here and can be used by security researchers to deobfuscate DEV#POPPER intermediary stages and final payloads like the DEV#POPPER RAT loader and DEV#POPPER RAT itself.
To learn how your organization can build cyber resilience and prevent business disruption with eSentire’s Next Level MDR, connect with an eSentire Security Specialist now.
GET STARTEDThe eSentire Threat Response Unit (TRU) is an industry-leading threat research team committed to helping your organization become more resilient. TRU is an elite team of threat hunters and researchers that supports our 24/7 Security Operations Centers (SOCs), builds threat detection models across the eSentire XDR Cloud Platform, and works as an extension of your security team to continuously improve our Managed Detection and Response service. By providing complete visibility across your attack surface and performing global threat sweeps and proactive hypothesis-driven threat hunts augmented by original threat research, we are laser-focused on defending your organization against known and unknown threats.