DPRK-aligned hackers hid malware inside SVG flag images to backdoor developer job interview coding tests. Not one antivirus vendor caught it.
Elastic Security Labs found a new Contagious Interview campaign, tracked as REF9403, hiding malware inside SVG image files using steganography. To our knowledge, this specific infection chain has not been previously documented. We found it after the DPRK-aligned group targeted our own community Slack workspace with a fake job posting and a "coding challenge" project.
Any user who ran the project ended up with a four-stage payload aligned with OTTERCOOKIE: a browser credential and crypto wallet stealer, a file stealer, a Socket.IO-based remote access trojan (RAT), and a clipboard stealer. This campaign reinforces that developers remain a prime target, where the compromise of a single individual can provide the initial access needed to enable far-reaching supply chain attacks against downstream organizations.
This investigation started differently from most of our research. Instead of using telemetry to surface interesting threats, we were alerted to suspicious activity targeting members of our community Slack workspace with socially engineered, ad hoc job offers. For background, we use the community Slack platform to engage with and solve problems for our users, focusing on providing product support and syncing on new updates.
We’ve reported on this technique several times : threat actors targeting developers in open forums with lures of coding side-work. The lucrative offers lead to the requirement to load specific libraries, tools, scripts, etc., into the code the developer is crafting. These components are created by the threat actors and once they’re executed by the developers, they are able to load additional malware and gain remote access to the developer host. From there, the threat actors can steal credentials, keys, wallets, or use the access to gain access to additional systems. We did not find evidence that the lures were targeted at Elastic users specifically, but any open forum where developers congregate is a potential watering hole.
On May 26, 2026, a user named Maxwell posted in our #jobs channel, stating that they were upgrading an e-commerce platform and were looking for an experienced developer to help with the project. They strategically moved their interactions with interested users into direct messages (DM).
In these direct messages, Maxwell requested that users perform a test challenge as part of the job offer. These recipients were given a trojanized repository that, when executed, contained malware that exfiltrated sensitive files and credentials and configured a Socket.IO backdoor.
Building on this initial case, we found multiple campaigns exhibiting the same underlying behavior. These trojanized repositories at the time of writing have zero detections and are not flagged by any AV vendors:
These fake challenges operate similarly, containing fully functional code. Our first sample was a .js e-commerce template that was copied from GreatStackDev called GoCart .
The threat actors tampered with this repository by inserting small snippets of malicious code at various points and using benign variable names to hide their intent. One of the major contributors to this scheme was their use of steganography in SVG images to hide chunks of the malware. While these legitimate-looking projects run perfectly fine, the malicious code is triggered silently behind-the-scenes.
The payloads are split into Base64 fragments inside HTML across every SVG flag image inside an assets directory. These files look like normal images of country flags ( AE.svg , AF.svg ), but each file contains an injected block with Base64-encoded data.
A JavaScript file in the repo ( serverValidation.js ) reassembles these chunks from every flag in alphabetical order to build the malicious payload.
The malware then decodes this data with a custom Base64-decoding function, Check() , and then uses eval() , avoiding simple detections that might trigger when using the Buffer.from method or the atob() function.
On every server start, the file ( server/index.js ) calls runServerValidation() after the initial middleware setup. As defined in the project's package.json , both npm run dev and npm start launch server/index.js , so the payload executes on each server boot.
Unfortunately, this kind of scam is working against developers. Some users have reported suspicious behavior after running the test challenges, while others have pushed these repos to GitHub unknowingly, not aware of the backdoored code.
Our team collected each trojanized repository, extracted the C2 servers, and analyzed each chain. The malicious payloads overlap with public reporting on DPRK/Contagious Interview, based on code similarity, behavior and related infrastructure.
The main payload in these repositories shares code similarity with the malware known as OTTERCOOKIE , first discovered by NTT Security in December 2024. Many of the strings, behavior, and script layout match those in publications, such as this blog post from Microsoft . While the malicious JavaScript code contains slightly different modifications, the underlying behaviors remain, with many matching strings.
The observed API endpoints in our samples also match recently linked infrastructure by the JFrog Security research team:
Analyzing this threat actor's activity is complicated by overlapping capabilities among related malware families. Their rapid evolution makes clean distinctions hard to maintain. Historically, BEAVERTAIL functioned as a first-stage stealer and downloader while OTTERCOOKIE served as a later-stage, C2-driven infostealer and RAT. Our observed samples reflect a convergence toward an all-in-one package that combines a Socket.IO-based RAT, a clipboard stealer, and a consolidated credential, wallet, and file stealer, with no Python stage present. On this basis, we lean toward using the OTTERCOOKIE naming convention, while noting that the boundary between the two is no longer clear.
The following section will cover the technical analysis of the malware.
This JavaScript malware is protected by obfuscator.io , which uses various techniques to prevent static analysis, such as string array extraction with index-based lookups to hide strings, a self-rotating array for anti-tampering, and other toolmarks, such as an infinite loop using while (!![]) .
There are 4 main modules that get launched at the start of execution:
This first module exfiltrates browser-based credentials and crypto wallet extension data across Windows, macOS, and Linux platforms. This module sets its process title to npm-cache , masquerading as a benign npm caching process to avoid suspicion in Windows Task Manager or process listings. The malware detects the operating system at runtime, then enumerates the following browsers based on their file paths:
For each browser profile found, the malware exfiltrates saved credentials ( Login Data ), autofill data ( Web Data ), and cryptocurrency wallet extension databases ( Local Extension Settings ).
This data is submitted via multipart HTTP POST requests to the /upload endpoint on the domain ldb.rightwidth[.]dev using the User Agent axios/1.18.1 .
Below is an example of the network request:
OTTERCOOKIE contains a hard-coded list of cryptocurrency wallet browser extension IDs. If a matching extension is found, the malware uploads the associated LevelDB stores to the C2 server via POST requests to the /cldbs endpoint of the domain ( ldb.rightwidth[.]dev ).
In our sample, the developer has added a prioritization check if the found extension path is in the first 8 targeted wallets. If so, these file paths receive special treatment: they are added to a monitored path array and trigger a separate workflow in which they are acknowledged by the C2 server and retried until successful. The remaining wallet extensions use a fire-and-forget approach with no acknowledgment or retries.
The list of 25 targeted browser extensions used by this module is in the Appendix.
For macOS machines, the system keychain database is also exfiltrated through this module.
This module performs a recursive file sweep targeting various documents and files from developer machines. On Windows, this module is more aggressive and has a larger blast radius, while on macOS/Linux, drive enumeration is skipped and it only targets directories.
Before scanning, the malware enumerates the mounted drives on the system using the following WMI query: wmic logicaldisk get name
, the malware scans each collected root drive from the wmic query or the directories on other platforms, searching for the following files whose names match a set of glob patterns:
In addition, any file whose path contains one of the following credential-store or shell-history locations is collected regardless of its extension:
Ultimately, this file stealer targets sensitive information stored on developer machines, including credentials, configuration files, shell histories, documents, images, and source code.
If any of the file patterns get matched, the files are sent through POST requests to the /upload endpoint using the domain ( upload.rightwidth[.]dev ). The files themselves aren’t additionally encrypted or compressed by the malware when sent over the network.
Below is an example of a .txt exfiltrated through this module:
The following file extensions and file paths are excluded from this file exfiltration module. There is a deliberate scoping decision in which the threat actors seek to maximize their signal and minimize noise. The list also confirms that this group is in tune with the current developer ecosystem, avoiding AI coding tooling extensions such as .claude , .cursor , .gemini , or .windsurf .
This third stage establishes a persistent Socket.IO command-and-control channel to the domain ( controller.rightwidth[.]dev ) over HTTPS. The malware ensures only one instance runs by enforcing a PID lock by writing its own process ID to a lock file in the user’s directory ( C:\Users\jim\.npm\vhost.ctl ).
The malware includes VM/sandbox detections for the different platforms. If there is a match, the malware places a tag in the C2 response with (VM) but does not stop or prevent it from running. This is likely used as a filtering mechanism to prioritize real victim machines over sandboxes/VMs.
The following table defines the VM detection mechanisms for each platform:
A registration beacon is sent to the domain ( controller.rightwidth[.]dev ) using endpoint /api/service/process/ . This includes the system host information, letting the threat actor know a new victim has been added.
The malware uses a logging channel ( /api/service/makelog ), which keeps the operator informed of the implant’s health and any errors.
The operator sends a command event containing a shell command, which the implant executes via child_process.exec() and returns the output as a message event over the same Socket.IO connection. This gives the operator interactive shell access to the victim machine in real time. Below is an example response from a victim machine running whoami :
The fourth module contains two separate capabilities: Windows dropper functionality and a clipboard stealer.
The dropper component is Windows-only and downloads three second-stage binaries via curl from file.rightwidth[.]dev , each disguised as a .txt file, then renamed to .exe before execution. The C2 server was unavailable at the time of analysis, so the payloads could not be retrieved. Based on their naming convention, they may relate to additional discovery or enumeration capabilities, but this is unconfirmed.
The clipboard functionality is only available on macOS and Windows. The malware polls every 500ms for new clipboard content, exfiltrating any changes to the C2 server ( rightwidth[.]dev ) via POST requests using endpoint ( /api/service/makelog/ ).
For macOS devices, pbpaste is used to retrieve the clipboard contents from victim machines.
On Windows, a new PowerShell process is spawned every 500ms via Get-Clipboard to retrieve the current clipboard contents. Below is an example process tree showing the clipboard module in action:
Developers remain a high-value target, with campaigns like these likely seeking to establish an initial foothold that can ultimately enable larger supply chain compromises. The success of these operations underscores how compromising an individual developer can provide a path to much broader organizational impact.
Elastic uses the MITRE ATT&CK framework to document common tactics, techniques, and procedures that threats use against enterprise networks.
Tactics represent the why of a technique or sub-technique. It is the adversary’s tactical goal: the reason for performing an action.
Techniques represent how an adversary achieves a tactical goal by performing an action.
The following observables were discussed in this research.
The following were referenced throughout the above research:
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
