Go to Top

Go to Top

Threat Intelligence

Threat Intelligence

Threat Intelligence

Contagious Interview Campaign Abusing VSCode Distributed on Github

Contagious Interview Campaign Abusing VSCode Distributed on Github

Contagious Interview Campaign Abusing VSCode Distributed on Github

ENKI WhiteHat

ENKI WhiteHat

Feb 27, 2026

Feb 27, 2026

Feb 27, 2026

Content

Content

Content

Executive Summary

  • ENKI identified and analyzed malware on Github that abuses Visual Studio Code (VS Code) automation features.

  • The distributed malware payloads include BeaverTail, InvisibleFerret, and OtterCookie, which are associated with the DPRK-nexus Contagious Interview campaign.

  • Artifacts indicate that threat actors used Large Language Models (LLMs) to generate portions of the malicious code.

  • Threat actors distributed the malware by masquerading as recruiters, developers, and fictitious companies to establish trust.

  • We identified and analyzed additional command-and-control (C&C) infrastructure based on the characteristics of the initial C&C servers.

1. Overview

We recently identified multiple instances of malware on Github that abuse VS Code automation features. Our analysis attributes this activity to Contagious Interview, a DPRK-nexus campaign active since at least 2025-08 that primarily targets developers.

In this campaign, threat actors typically pose as recruiters to approach targets. Under the guise of coding tests or video interviews, they lure victims into downloading malicious payloads such as BeaverTail, InvisibleFerret, and OtterCookie.

The Github accounts identified in this investigation purported to be recruiters for legitimate companies, Web3 developers, and fictitious organizations. The threat actors likely employed these personas to blend in with normal recruitment and development activities, establishing trust to facilitate malware distribution.

Furthermore, our analysis of the deployed malware revealed artifacts suggesting the code was generated using LLMs. This indicates that the threat actors are actively using AI technologies to develop malicious tools more efficiently and complicate reverse engineering efforts.

This report examines the threat actors' Github activities and details the operational mechanisms and capabilities of the malware used in these attacks.

Github Activity

2.1. Impersonating Legitimate Companies

In one instance, threat actors impersonated a recruiter from Koinos, a Web3 company, to distribute malware via repositories related to coding tests.

Although the account profile is now unavailable, multiple forked repositories intended for coding assessments created by the actor under the handle "andrew" remain accessible.

Coding test-related repositories

caption - Coding test-related repositories

Commands designed to download and execute malware were present in the .vscode/tasks.json file across all repositories. This technique abuses VS Code's automation features, automatically downloading and executing malware when the repository is opened in the editor.

Scripts embedded in .vscode/tasks.json

caption - Scripts embedded in .vscode/tasks.json

Eleven repositories containing commits from the "andrew" account remain accessible. Commit history analysis revealed the actor also operated under the name "andrew_watson" and used the email address andrew@koinos[.]us.

Example of commit history

caption - Example of commit history

The koinos[.]us domain closely resembles the legitimate Koinos domain (koinos.io). Although the exact distribution vector is unknown, the repository names frequently included terms like "koinos", "assessment", and "dev-test". Therefore, we assess the threat actors distributed malware by impersonating corporate recruiters and using the hiring process as a lure.

2.2. Masquerading as Developers

In another instance, threat actors masqueraded as developers to inject malicious commands into public repositories. We identified five accounts, all posing as full-stack developers with purported experience in Web3 projects:

  • ameeetgaikwad

  • dannythedawger

  • yosket

  • nikkhielseath

  • jmjles

jmjles account profile

caption - jmjles account profile

We identified 10 repositories with injected commands:

  • Token-Presale-dApp

  • Promoting-DApp

  • dapp-integration

  • Web3-RE-Prototype

  • TrustLedger_Fixes

  • linkfi

  • testtoken

  • messageforge

  • Token-Presale

  • Decentralized-Social

The "yosket" and "nikkhielseath" accounts have been deleted, but the remaining three accounts remain active.

The malicious commands were embedded in the .vscode/tasks.json file. By leveraging public repositories, threat actors could infect victims without relying on direct social engineering lures.

Script embedded in .vscode/tasks.json

caption - Script embedded in .vscode/tasks.json

The most active account, "yosket", was deleted but showed activity until 2026-01-16.

yosket's commit history on 2026-01-16

caption - yosket's commit history on 2026-01-16

Furthermore, analysis of yosket's activity revealed the 10 specific repository URLs where the account injected malicious commands:

  • hxxps://github[.]com/TrustLedgerLabs/Token-Presale-dApp

  • hxxps://github[.]com/ryon-business/Promoting-DApp

  • hxxps://github[.]com/angel-group888/dapp-integration

  • hxxps://github[.]com/AretaSchmidt/Web3-RE-Prototype

  • hxxps://github[.]com/QalbeAli/TrustLedger_Fixes

  • hxxps://github[.]com/trustllabs/Token-Presale-dApp

  • hxxps://github[.]com/DavidMoura07/linkfi

  • hxxps://github[.]com/VictorKulagin/testtoken

  • hxxps://github[.]com/rajaXcodes/Token-Presale-dApp

  • hxxps://github[.]com/Rochelle128/TokenPresaleDApp

The other four accounts collaborated on the same projects. Notably, within the "messageforge" repository, we observed coordinated activity between two accounts.

nikkhielseath account commit history in the messageforge repository

caption - nikkhielseath account commit history in the messageforge repository

In addition to the commands responsible for downloading and executing the primary payload, the .vscode/tasks.json file included a command to execute .vscode/spellright.dict using Node.js. The vscode/spellright.dict file is a JavaScript payload obfuscated using obfuscator.io and committed by "ameeetgaikwad".

.vscode/spellright.dict file added by ameeetgaikwad

caption - .vscode/spellright.dict file added by ameeetgaikwad

2.3. Fictitious Company Operations

In a third instance, threat actors injected malicious commands into repositories belonging to a purported company. Our investigation revealed this was a fictitious organization designed to appear legitimate through a dedicated website and LinkedIn profiles.

ictitious company account veneliteus-dev

caption - ictitious company account veneliteus-dev

Identical malicious commands were embedded in the .vscode/tasks.json file across all three identified repositories. All changes were committed on 2026-01-14, indicating a coordinated effort.

The actors concealed the commands using whitespace padding.

Malicious script embedded in .vscode/tasks.json

caption - Malicious script embedded in .vscode/tasks.json

The website linked in the "veneliteus-dev" account profile is currently accessible but non-functional. It contains four social media links; however, only the LinkedIn link points to a specific profile, while the others (Facebook, Instagram, X) redirect to the platforms' main pages.

hxxps://veneliteus[.]com

caption - hxxps://veneliteus[.]com

Venelitus 링크드인

caption - Venelitus LinkedIn

Additionally, the website's contact form is non-functional, displaying a "Message sent!" notification without transmitting any data.

Although the exact distribution vector is unknown, we assess the threat actors likely employed social engineering strategies similar to those used in the legitimate company impersonation.

3. Attack Analysis

Attack Overview Diagram

caption - Attack Overview Diagram

The attack flow for this Contagious Interview campaign diverges into two paths. Depending on the target environment or attack stage, threat actors deployed either a combination of BeaverTail and InvisibleFerret, or OtterCookie independently.

3.1. BeaverTail and InvisibleFerret

3.1.1. task.json - Downloader

This downloader is executed via VS Code. The runOn option within runOptions is set to folderOpen, ensuring the embedded command executes automatically when the repository is opened in the editor.

Command hidden via long whitespace in .vscode/tasks.json

caption - Command hidden via long whitespace in .vscode/tasks.json

The configuration contains OS-specific commands for Linux, macOS, and Windows. The appropriate command downloads and executes a script from the command-and-control (C&C) server.

Embedded commands

caption - Embedded commands

While the download URLs vary by operating system, the downloaded scripts for Linux and macOS are identical. All scripts download and execute a subsequent payload.

On Linux and macOS, the malware downloads a shell script to $HOME/Documents/tokenlinux.npl. It then renames the file to tokenlinux.sh and executes it.

Linux and macOS download script

caption - Linux and macOS download script

On Windows, the malware downloads a CMD script to %USERPROFILE%/parse. It then renames the file to token.cmd and executes it.

Windows download script

caption - Windows download script

During our analysis, we could not obtain the Windows CMD script because the server returned an "Access permanently suspended." error.

3.1.2. tokenlinux.sh - Downloader

The tokenlinux.sh file, executed on Linux and macOS, is a downloader that we assess was generated using a Large Language Model (LLM).

Unlike scripts previously observed in Contagious Interview campaigns, this script features highly detailed comments and incorporates emojis, patterns strongly indicative of LLM-assisted generation.

Detailed comments including emojis

caption - Detailed comments including emojis

tokenlinux.sh checks for the presence of a nodejs directory in the current directory. If absent, it downloads and extracts Node.js, then adds it to the system PATH. It then proceeds to download parser.js and package.json from the C&C server, saving them to the $HOME/Documents directory.

Finally, the script executes parser.js using the downloaded Node.js environment. The accompanying package.json contains the package dependencies required to run parser.js.

3.1.3. - parser.js - Downloader

parser.js is a JavaScript-based downloader obfuscated using obfuscator.io. The primary obfuscation techniques applied include:

  • String Extraction and Arraying: Key strings used in the code are extracted and stored in a separate array.

  • Runtime Array Shuffling: The string array is reordered at the beginning of execution.

  • Offset-based String Access: Strings are not referenced directly; instead, they are retrieved from the array using a dedicated function that takes an offset value as an argument.

  • Identifier Renaming: Meaningful variable and function names are replaced with short, meaningless identifiers such as a1.

Obfuscated script

caption - Obfuscated script

In addition to obfuscation, the script employs integrity checks. If the code is modified or formatted (e.g., pretty-printed), the script executes dummy code and errors.

Integrity check function

caption - Integrity check function

The malware communicates with two distinct C&C servers:

  • Configuration Server: Hosts configuration data required to download BeaverTail (the payload server address and a campaign ID).

  • Payload Server: Hosts the BeaverTail payload.

The script contains two Base64-encoded Configuration Server addresses. If communication with the primary Configuration Server fails, it falls back to the secondary address.

Configuration Server address decoding routine

caption - Configuration Server address decoding routine

If the response from hxxp://[Configuration Server]:1244/s/6df937fe9011 begins with ZT3, the script Base64-decodes the remainder of the string. The decoded value is split by a comma (,); the first part is the Payload C&C address, and the second part is the campaign ID. As of 2026-01-26, the Payload C&C address was 66.235.175[.]117 and the campaign ID was knHbMe8.

Payload Server address decoding routine

caption - Payload Server address decoding routine

Strings are decrypted using XOR with the key 0x70a07948.

String decryption routine

caption - String decryption routine

The malware download and execution process is as follows:

  1. Creates a .vscode directory in the home directory

  2. Transmits the hostname, username, and current timestamp to hxxp://[Payload Server]:1244/key

  3. Downloads BeaverTail from hxxp://[Payload Server]:1244/j/[Campaign ID] to .vscode/test.js

  4. Downloads the package metadata from hxxp://[Payload Server]:1244/p to .vscode/package.json

  5. Executes .vscode/test.js.

This download routine repeats three times at approximately 10-minute intervals.

3.1.4. Beavertail

BeaverTail consists of three JavaScript files. The initial script, test.js, downloads and executes the remaining two files. All BeaverTail scripts employ the same obfuscation and anti-tampering techniques observed in parser.js.

test.js

This script collects browser information and downloads and executes n.js and p.js. It targets the following browsers:

  • Chrome

  • Chromium

  • Brave

  • Opera

It extracts stored credentials and browser extension data, uploading the information to hxxp://66.235.175[.]117:1244/uploads. The script specifically targets the following browser extension IDs:

| list | list |
| --- | --- |
| nkbihfbeogaeaoehlefnkodbefgpgknn | ejbalbakoplchlghecdalmeeeajnimhm |
| ibnejdfjmmkpcnlpebklmnkoeoihofec | fhbohimaelbohpjbbldcngcnapndodjp |
| hnfanknocfeofbddgcijnmhnfnkdnaad | bfnaelmomeimhlpmgjnjophhpkkoljpa |
| aeachknmefphepccionboohckonoeemg | egjidjbpglichdcondbcbdnbeeppgdph |
| hifafgmccdpekplomjjkcfgodnhcellj | aholpfdialjgjfhomihkjbmgjidlcdno |
| mcohilncbfahbmgdjkbpemcciiolgcge | pdliaogehgdbhbnmkklieghmmjkpigpa |
| nphplpgoakhhjchkkhmiggakijnkhfnd | fdjamakpfbbddfjaooikfcpapjohcfmg |
| acmacodkjbdgmoleebolmdjonilkdbch | dmkamcknogkgcdfhhbddcghachkejeap |
| mkpegjkblkkefacfnmkajcjmabijhclg | X

caption - Target browser extensions for information collection

Upon successful upload, it downloads a file from hxxp://66.235.175[.]117:1244/client/knHbMe8 and saves it as .npl. This file is InvisibleFerret, which is executed via Python. If the operating system is Windows, it downloads Python from hxxp://66.235.11[.]117:1244/pdo to execute the .npl file.

.npl file download routine

caption - .npl file download routine

After executing InvisibleFerret, it downloads the remaining BeaverTail components from hxxp://66.235.11[.]117:1244/n/knHbMe8 and hxxp://66.235.11[.]117:1244/z/knHbMe8 to .vscode/n.js and .vscode/p.js respectively, and executes them.

Additional BeaverTail download routine

caption - Additional BeaverTail download routine

n.js

This is a backdoor component. It first collects system information and uploads it to hxxp://66.235.175[.]117:1244/keys. The collected data includes:

  • IP-based geolocation data

  • ISP information

  • A UUID generated by HMAC-hashing the username

  • Hostname

  • Username

  • OS type

  • OS release

  • OS version

Following the upload, it establishes a socket connection with the C&C server at 216.250.251[.]87:1247.

Socket connection routine

caption - Socket connection routine

Once connected, it receives a code value from the C&C server and performs actions based on the code:

| Code | Command Name | Action |
| --- | --- | --- |
| 1    | ssh_obj      | Execute given command (Remote Shell)                                    |
| 2    | ssh_cmd      | Terminate the current process                                           |
| 5    | ssh_upload   | Upload specified file or directory via FTP                              |
| 6    | ssh_kill     | Terminate Chrome and Brave processes                                    |
| 8    | ssh_env      | Searches for and uploads all files matching specific conditions via FTP |
| 10   | ssh_mmc      | Saves the provided JavaScript file to ~/.vscode/c.js and executes it

caption - Backdoor Actions

For FTP uploads, the C&C server provides the domain, username, and password. The upload path format is /DAknHbMe8/[Hostname]+[Username]/[Filename].

FTP upload routine

caption - FTP upload routine

The ssh_env command searches for and uploads files containing specific strings in their paths:

| list | list |
| -- | -- |
| .env | .xls |
| config.js | .xlsx |
| secret | .doc |
| metamask | .docx |
| wallet | .rtf |
| private | .kbdx |
| mnemonic | .one |
| password | .onenote |
| account | solana |
| seed | X

caption - Search String List

It avoids uploading files with specific names or extensions (e.g., tsconfig.json) and skips certain directories (e.g., node_modules). A comprehensive list is included in "Appendix C. Search Conditions".

p.js

This component performs file collection and exfiltration. It searches for and exfiltrates files matching the following patterns:

| list | list |
| --- | --- |
| *.env | seed* |
| config.js | keys* |
| secret* | keypair.json |
| metamask* | 1pass*.sqlite |
| wallet* | notes.txt |
| private* | hardhat.config.ts |
| mnemonic* | solana* |
| password* | .kdbx |
| account* | X

caption - Search Pattern List

Similar to n.js, it skips specific directories and file extensions. A comprehensive list is included in "Appendix C. Search Conditions".

Upload file search routine

caption - Upload file search routine

Files are exfiltrated to hxxp://66.235.175[.]117:1244/uploads using a POST request structured as follows:

{
  "timestamp": "jzt",
  "type": "knHbMe8",
  "hid": "[Hostname]",
  "multi_file": {
    "value": "[File Stream]",
    "options": {
      "filename": "env_[Current Time]_[Random Number 0-40]_[File Index]"

The [File Index] represents the file's position within the list generated during the search. Upon successful upload, the file path and hostname are sent to hxxp://66.235.175[.]117:1244/keys in the following format:

{
  "ts": "jzt",
  "type": "knHbMe8",
  "hid": "[Hostname]",
  "ss": "jzt_[Search Pattern]_[Current Time]",
  "cc": "env_[Current Time]_[Random Number 0-40]_[File Index] : [File Path]"

3.1.5. InvisibleFerret

InvisibleFerret is a Python-based malware consisting of five scripts. All scripts are obfuscated using the following multi-layered routine:

  1. Decodes a Base85 string located after the first 8 characters of the obfuscated payload

  2. XORs the decoded result with the first 8 characters and executes it via exec

  3. The executed code reverses a new string, Base64-decodes it, decompresses it via zlib, and executes it via exec.

  4. Step 3 is repeated approximately 64 times before the actual malicious script is executed.

.npl

This is the initial InvisibleFerret script executed by BeaverTail. It downloads and executes two additional scripts.

Script download and execution routine

caption - Script download and execution routine

It downloads a payload from hxxp://66.235[.]175.117:1244/payl/knHbMe8, saves it as .vscode/pay, and executes it. It then downloads an additional payload from hxxp://66.235[.]175.117:1244/bro/knHbMe8 to .vscode/bow, and executes it. If the operating system is Darwin(macOS), the bow file is not downloaded.

pay

This is a backdoor that performs malicious actions based on code values received via a socket connection to the C&C server (216.250.251[.]87:1245).

Socket connection routine

caption - Socket connection routine

The supported commands are:

| Code | Name | Action |
| --- | --- | --- |
| 1    | ssh_obj    | Execute provided command                                                         |
| 2    | ssh_cmd    | Self-destruct                                                                    |
| 3    | ssh_clip   | Transmit keylogging and clipboard data.                                          |
| 4    | ssh_run    | Download hxxp://66.235.175[.]117:1244/bro/knHbMe8 to ~/.n2/bow and execute   |
| 5    | ssh_upload | Uploads file from provided path                                                  |
| 6    | ssh_kill   | Terminate Chrome and Brave browser processes                                     |
| 7    | ssh_any    | Download hxxp://66.235.175[.]117:1244/adc/knHbMe8 to ~/.n2/adc and execute   |
| 8    | ssh_env    | Search for and upload all files matching conditions via FTP                      |
| 9    | ssh_zcp    | Compress provided file into an encrypted archive and upload via Telegram and FTP |
| 10   | ssh_mmc    | Download hxxp://66.235.175[.]117:1244/dd/knHbMe8 to ~/.n2/mc and executes    |

caption - Backdoor Actions

The ssh_env command targets files containing the following strings in their paths:

| list | list |
| --- | --- |
| env | .xls |
| config.js | .xlsx |
| secret | .doc |
| metamask | .docx |
| wallet | .rtf |
| private | .kbdx |
| mnemonic | .one |
| password | .onenote |
| account | X

A comprehensive list is included in "Appendix C. Search Conditions".

bow

This script drops an obfuscated TsunamiInjector payload into the Windows Startup folder to establish persistence.

Script save routine

caption - Script save routine

The TsunamiInjector script decrypts and visits approximately 1,000 encrypted URLs to identify those that are available. The decryption process is as follows:

  • Hex-decode the string

  • XOR the decoded string with the key !!!HappyPenguin1950!!!

  • Base64-decode the result and reverse the string

URL decryption routine

caption - URL decryption routine

All decrypted URLs point to Pastebin, a popular text-sharing platform. Once an available Pastebin URL is found, it decrypts the page's contents using the same method. The decrypted content yields another URL which is downloaded and extracted to %APPDATA%\Microsoft\Windows\Applications\Runtime Broker.exe.

File download routine

caption - File download routine

After downloading, it adds the file path to Windows Defender exclusions and establishes persistence by creating a scheduled task to execute the payload on user login.

Task creation routine

caption - Task creation routine

adc

This script downloads AnyDesk, a remote desktop application, from hxxp://66.235.175[.]117:1244/and. It then configures the password, allowing the threat actor to connect remotely at any time.

AnyDesk configuration routine

caption - AnyDesk configuration routine

mc

This script manipulates the browser environment to install a malicious cryptocurrency wallet extension. It performs self-deletion upon execution.

Self-deletion routine

caption - Self-deletion routine

It enumerates the extension directories of Chrome and Brave, deleting all files associated with specific extensions. The targeted extension IDs are:

  • nkbihfbeogaeaoehlefnkodbefgpgknn

  • acmacodkjbdgmoleebolmdjonilkdbch

After deletion, it downloads a payload from hxxp://45.59.163[.]55:1244/mmz/[Extension ID]_knHbMe8 and extracts it into the now-empty extension directories. This effectively replaces the legitimate Rabby Wallet and MetaMask cryptocurrency wallet extensions with malicious versions.

Browser extension file modification routine

caption - Browser extension file modification routine

The malware then collects the Chrome profile file and exfiltrates it to hxxp://45.59.163[.]55:1244/h. If the server returns a valid response, the script uses the response data to modify Chrome's Secure Preferences.

Additionally, on macOS with Chrome 140 or higher, it attempts to downgrade the browser by downloading and extracting hxxp://45.59.163[.]55:1244/ddo to /Applications/Google Chrome.app, overwriting it.

Chrome downgrade routine

caption - Chrome downgrade routine

Once the configuration changes are complete, it clears the browser's cookies, cache, and session data to apply the changes immediately. It then reports the success status to hxxp://66.235.175[.]117:1244/t.

3.2. OtterCookie

3.2.1. task.json - Downloader

Similar to the BeaverTail and InvisibleFerret instance, this downloader is executed via VS Code. The runOn option is set to folderOpen, triggering execution when the repository is opened. However, unlike the previous cluster, the commands in this tasks.json file are not hidden with long whitespace.

Command embedded in .vscode/tasks.json

caption - Command embedded in .vscode/tasks.json

Although the download URLs vary by operating system, the Linux and macOS scripts are identical. All scripts download and execute a subsequent payload.

On Linux and macOS, it downloads a shell script to $HOME/.vscode/vscode-bootstrap.sh and executes it.

Shell script executed on Linux and macOS

caption - Shell script executed on Linux and macOS

On Windows, it downloads a CMD script to %USERPROFILE%\.vscode\vscode-bootstrap.cmd and executes it.

CMD script executed on Windows

caption - CMD script executed on Windows

During our analysis, we could not obtain the Windows CMD script because the server returned an "Access permanently suspended." error.

3.2.2. vscode-bootstrap.sh - Downloader

The vscode-bootstrap.sh script executed on Linux and macOS is a downloader. Like tokenlinux.sh, we assess it was generated using an LLM, though it lacks the emoji usage seen previously.

Shell script with detailed comments

caption - Shell script with detailed comments

It checks for a nodejs directory in the current path. If absent, it downloads and extracts Node.js. It then downloads env-setup.js and package.json from the C&C server to $HOME/.vscode. Finally, it executes env-setup.js using the downloaded Node.js.

3.2.3. env-setup.js - Downloader

env-setup.js is a downloader that connects to hxxps://y-lilac-sigma.vercel[.]app/api/ipcheck-encrypted/608 and executes the response via eval. Notably, it executes the payload only when an error occurs, rather than upon receiving a HTTP 200 OK response.

env-setup.js code

caption - env-setup.js code

3.2.4. OtterCookie

OtterCookie is downloaded and executed via env-setup.js. It employs the same obfuscation and integrity checking techniques observed in BeaverTail.

OtterCookie executes three distinct scripts stored as strings in separate processes. To prevent duplicate execution, it creates lock files containing the process PID and start time ({ pid: [Process PID], startedAt: [Process Start Time] }). The lock files and their corresponding scripts are detailed below:

| Lock File Name | Script Name      | Action                                            |
| -------------- | ---------------- | ------------------------------------------------- |
| pid.6.1.lock   | ldbScript        | Exfiltrates information stored in browsers.       |
| pid.6.2.lock   | autoUploadScript | Searches for and uploads specific files.          |
| pid.6.3.lock   | socketScript     | Connects to the C&C server and executes commands

caption - Lock and script information

ldbScript

This script collects credentials and extension data from browsers. Targeted browsers include:

| list | list |
| --- | --- |
| Chrome | Kiwi |
| Brave | Yandex |
| AVG Browser | Iridium |
| Edge | Comodo |
| Opera | SRWare |
| Opera GX | Chromium |
| Vivaldi | X

caption - Targeted browsers for information collection

Targeted browser extensions include:

| list | list |
| --- | --- |
| 1nkbihfbeogaeaoehlefnkodbefgpgknn | fhkbkphfeanlhnlffkpologfoccekhic |
| ejbalbakoplchlghecdalmeeeajnimhm | fhmfendgdocmcbmfikdcogofphimnkno |
| acmacodkjbdgmoleebolmdjonilkdbch | fldfpgipfncgndfolcbkdeeknbbbnhcc |
| bfnaelmomeimhlpmgjnjophhpkkoljpa | gjnckgkfmgmibbkoficdidcljeaaaheg |
| ibnejdfjmmkpcnlpebklmnkoeoihofec | hifafgmccdpekplomjjkcfgodnhcellj |
| egjidjbpglichdcondbcbdnbeeppgdph | hmeobnfnfcmdkdcmlblgagmfpfboieaf |
| nphplpgoakhhjchkkhmiggakijnkhfnd | hnfanknocfeofbddgcijnmhnfnkdnaad |
| omaabbefbmiijedngplfjmnooppbclkk | jiidiaalihmmhddjgbnbgdfflelocpak |
| bhhhlbepdkbapadjdnnojkbgioiodbic | jblndlipeogpafnldhgmapagcccfchpi |
| aeachknmefphepccionboohckonoeemg | jmbkjchcobfffnmjboflnchcbljiljdk |
| aflkmhkiijdbfcmhplgifokgdeclgpoi | jnjpmcgfcfeffkfgcnjefkbkgcpnkpab |
| agoakfejjabomempkjlepdflaleeobhb | kpkmkbkoifcfpapmleipncofdbjdpice |
| aholpfdialjgjfhomihkjbmgjidlcdno | khpkpbbcccdmmclmpigdgddabeilkdpd |
| afbcbjpbpfadlkmhmclhkeeodmamcflc | ldinpeekobnhjjdofggfgjlcehhmanaj |
| cgbogdmdefihhljhfeffkljbghamglni | lgmpcpglpngdoalbgeoldeajfclnhafa |
| dmkamcknogkgcdfhhbddcghachkejeap | mcohilncbfahbmgdjkbpemcciiolgcge |
| dlcobpjiigpikoobohmabehhmhfoodbb | mopnmbcafieddcagagdcbnhejhlodfdd |
| efbglgofoippbgcjepnhiblaibcnclgk | nkklfkfpelhghbidbnpdfhblphpfjmbo |
| ejjladinnckdgjemekebdpeokbikhfci | penjlddjkjgpnkllboccdgccekpkcbin |
| fhbohimaelbohpjbbldcngcnapndodjp | ppbibelpcjmhbdihakflkdcoccbgbkpo

caption - Target browser extensions for information collection

autoUploadScript

This script scans all drives for files containing specific strings and uploads them to hxxp://172.86.73[.]198:8086/upload. A comprehensive list is included in "Appendix C. Search Conditions".

File upload routine

caption - File upload routine

Unlike ldbScript, this upload method does not include file metadata and uses the file path to generate an HMAC token.

autoUploadScript also features detailed comments and verbose console outputs that are hidden from the user, further suggesting it was generated using an LLM.

socketScript

This script collects system information and exfiltrates it to hxxp://172.86.73[.]198:8087/api/notify. The collected data format is as follows:

{
  "ukey": 608,
  "t": 6,
  "host": "608_[Hostname]",
  "os": "[OS Type]",
  "username": "[Username]",
  "timestamp": "[Current Time]"

It then establishes a socket connection with the C&C server at 172.86.73[.]198:8087. It performs actions based on messages received from the C&C server:

| Message        | Action                                                  |
| -------------- | ------------------------------------------------------- |
| whour          | Send the previously collected system information        |
| command        | Execute provided command                                |
| disconnect     | Terminate the socket connection and enter standby state |
| reconnect      | Re-establish the socket connection                      |
| processControl | Manipulate other OtterCookie processes

caption - Actions for messages

The processControl command is designed to pause or restart ldbScript, autoUploadScript, and socketScript; however, only the stop functionality is currently implemented.

Incomplete processControl function

caption - Incomplete processControl function

Similar to the other components, socketScript contains detailed comments and verbose console outputs, indicating LLM-assisted generation.

Additional C&C Servers

The C&C servers associated with BeaverTail and InvisibleFerret share the following characteristics:

  1. An HTTP server is running on port 1244.

  2. Ports 21 (FTP) and 3389 (RDP) are open.

  3. The infrastructure primarily relies on Virtual Private Server (VPS) hosting providers.

  4. Accessing hxxp://[C&C Server]:1244/p returns a package.json file.

Based on the first three characteristics, we initially identified 18 related IP addresses using Censys.

Censys search results

caption - Censys search results

We then verified these IPs by checking the response from hxxp://[IP]:1244/p, ultimately confirming 10 active C&C servers. The identified C&C servers are detailed in the table below:

| Server IP         | Campaign ID | Hosting Information                       |
| ----------------- | ----------- | ----------------------------------------- |
| 216.250.251[.]211 |      -      | VPS hosted by Majestic Technosoft (India) |
| 45.59.163[.]23    |      -      | VPS hosted by Tier.Net (US)               |
| 38.92.47[.]152    |      -      | VPS hosted by Tier.Net (US)               |
| 103.65.230[.]100  |      -      | VPS hosted by EuroHoster (Bulgaria)       |
| 147.124.213[.]19  |      -      | VPS hosted by Majestic Technosoft (India) |
| 66.235.175[.]117  | knHbMe8     | VPS hosted by Tier.Net (US)               |
| 66.235.175[.]109  | ryGnMe8     | VPS hosted by Tier.Net (US)               |
| 147.124.202[.]225 |      -      | VPS hosted by Tier.Net (US)               |
| 67.203.7[.]205    | ZRj2s0k9    | VPS hosted by Colocation America (US)     |
| 147.124.213[.]232 | kmHgMq7     | VPS hosted by Majestic Technosoft (India)

caption - Additional C&C server list

All identified C&C servers utilize VPS hosting. Despite using different hosting providers, all IPs geolocate to the United States. Additionally, with the exception of 130.65.230[.]100, 66.235.175[.]117, and 66.235.175[.]109, port 445 (SMB) was open on the remaining IPs.

Furthermore, while most C&C servers dropped requests containing invalid campaign IDs, three servers (66.235.175[.]109, 38.92.47[.]152, and 45.59.163[.]23) returned responses.

Specifically, 38.92.47[.]152 returned an error message, whereas 66.235.175[.]109 and 45.59.163[.]23 echoed the invalid campaign ID back in the HTTP response.

We were unable to identify additional C&C servers for OtterCookie, as its infrastructure is protected by bulletproof hosting services.

5. Conclusion

This report details our analysis of a Contagious Interview campaign that abuses VS Code automation features via GitHub for malware distribution. The final-stage payloads include BeaverTail, InvisibleFerret, and OtterCookie. These tools are designed to exfiltrate sensitive information—including browser credentials and cryptocurrency wallet files—from infected systems. They also establish C&C communication to receive commands for remote control and the deployment of additional malware.

Developers should remain vigilant, as many development tools can automatically execute code upon opening a project. To mitigate this risk in VS Code, ensure the Workspace Trust feature is enabled (security.workspace.trust.enabled, which defaults to true). Furthermore, users should thoroughly audit both their editor configurations and workspaces before granting trust, paying particular attention to VS Code directories (.vscode), toolchains, and extension configurations.

Notably, this campaign highlights the threat actors' use of Large Language Models (LLMs) to generate malicious scripts, thereby increasing the efficiency of their tool development. The actors also relied on social engineering, impersonating legitimate corporate recruiters and masquerading as standard developers contributing to open-source projects. During our investigation, we identified multiple additional C&C servers, indicating that the threat actors are continuously expanding and maintaining their attack infrastructure.

The Contagious Interview campaign remains active, with DPRK-nexus threat actors persistently targeting developers and the open-source ecosystem, particularly on GitHub. The tactic of embedding malicious automation commands within repositories disguised as coding assessments, interview projects, and test code demonstrates the continuous evolution and sophistication of this campaign.

6. Appendix

Appendix A. MITRE ATT&CK

| Tactics | Techniques |
| --- | --- |
| Initial Access | T1566: Phishing-nT1195.001: Supply Chain Compromise: Compromise Software Dependencies and Development Tools |
| Execution | T1059: Command and Scripting Interpreter |
| Defense Evasion | T1027: Obfuscated Files or Information-nT1562.001: Disable or Modify Tools-nT1070.004: Indicator Removal: File Deletion |
| Persistence | T1547.001: Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder-nT1053.005: Scheduled Task/Job: Scheduled Task |
| Discovery | T1082: System Information Discovery-nT1083: File and Directory Discovery-nT1518: Software Discovery-nT1057: Process Discovery |
| Credential Access | T1555.003: Credentials from Password Stores: Credentials from Web Browsers-nT1056.001: Input Capture: Keylogging |
| Collection | T1115: Clipboard Data |
| Command and Control | T1071.001: Application Layer Protocol: Web Protocols-nT1071.002: Application Layer Protocol: File Transfer Protocols-nT1219.002: Remote Access Software: Remote Desktop Software-nT1102.001: Web Service: Dead Drop Resolver-nT1571: Non-Standard Port |
| Exfiltration | T1048: Exfiltration Over Alternative Protocol-nT1041: Exfiltration Over C2 Channel

caption - MITRE ATT&CK

Appendix B. IOCs

sha256

| sha256 | File Name |
| --- | --- |
|748b044a62787bf8341ac46208ac5c7703b0cf6d0fffdd2c76160244247cd930 | tokenlinux.sh|
|2f94573c15bfa1f945a0e1116b2373542d7a1dbc12dd58eb612078ddafbff54b | parser.js|
|a51b6b30d871acf43539ef4f19bfd1954a5db3f8422ed91fc14519ef60431296 | test.js|
|7e6ae216310d938218ff4fdf8bfe2e9a73d7684188705b97232e968022cc6b46 | n.js|
|50b14f2ea38cb7a388917394e8906712caf67acaf1c60ac6fab71072ef1eca3b | p.js|
|0f0b20e88511ae2014b0c90ed2dbbcaad7e5d9593b50fdd43081f24cb0d05534 | pay|
|9310f180e417a6cd5b505cdec0a726a9f0c39519687491d22bd98d917e0139f8 | bow|
|8e142c55f0af4961b59cb0dae027eeb256d173ba094afdf66d8fbf047f014169 | adc|
|572a75f932aecd2bcbe5eb4685e399e04688c94dd44a75db92d51618467a0d18 | mc|
|964885a574aa6287a55bfe6fdb1512d531b03c9e15609fe6782afbb0116f6fba | vscode-bootstrap.sh|
|1f97f7a0614685f2e8cd8347bf10cd7832b5dd9dce96e195e15da9b9b2be2e3e | env-setup.js|
|d7c36881f91c45b66b32ec0c80f2d49ff90d76d2d147f2d208c6eea48842618c | OtterCookie

caption - sha256

IP

  • 216.250.251[.]211

  • 216.250.251[.]87

  • 45.59.163[.]23

  • 45.59.163[.]55

  • 38.92.47[.]152

  • 103.65.230[.]100

  • 147.124.213[.]19

  • 66.235.175[.]117

  • 66.235.175[.]109

  • 147.124.202[.]225

  • 67.203.7[.]205

  • 147.124.213[.]232

  • 172.86.73[.]198

URL

  • hxxps://vscode-load-config.vercel[.]app/settings/mac?flag=4

  • hxxps://vscode-settings-config.vercel[.]app/settings/windows?flag=8

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/linux?flag=306

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/windows?flag=4

  • hxxps://www.vscodeconfig[.]com/settings/mac?flag=1

  • hxxps://www.vscodeconfig[.]com/settings/mac?flag=3

  • hxxps://vscodesettings03kui.vercel[.]app/api/settings/mac

  • hxxps://www.vscodeconfig[.]com/settings/windows?flag=3

  • hxxps://vscode-helper171.vercel[.]app/settings/linux?flag=4

  • hxxps://vscode-load-config.vercel[.]app/settings/linux?flag=4

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/linux?flag=301

  • hxxps://www.vscodeconfig[.]com/settings/mac?flag=4

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/mac?flag=302

  • hxxps://www.vscodeconfig[.]com/settings/linux?flag=1

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/linux?flag=6

  • hxxps://vscode-toolkit-bootstrap.vercel[.]app/settings/windows?flag=306

  • hxxps://vscode-settings-config.vercel[.]app/settings/linux?flag=606

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/windows?flag=306

  • hxxps://vscode-load.onrender[.]com/settings/linux?flag=5

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/windows?flag=302

  • hxxps://vscode-toolkit-bootstrap.vercel[.]app/settings/mac?flag=306

  • hxxps://vscode-settings-config.vercel[.]app/settings/mac?flag=8

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/mac?flag=3

  • hxxps://vscode-load-config.vercel[.]app/settings/linux?flag=1

  • hxxps://www.vscodeconfig[.]com/settings/windows?flag=4

  • hxxps://vscode-helper-132.vercel[.]app/settings/windows?flag=4

  • hxxps://vscode-helper-132.vercel[.]app/settings/linux?flag=4

  • hxxps://vscodesettingstask.vercel[.]app/api/settings/windows

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/mac?flag=306

  • hxxps://vscode-load-config.vercel[.]app/settings/windows?flag=1

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/linux?flag=302

  • hxxps://vscode-load.onrender[.]com/settings/windows?flag=5

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/mac?flag=308

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/windows?flag=6

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/windows?flag=301

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/windows?flag=305

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/mac?flag=305

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/linux?flag=308

  • hxxps://codeviewer-three.vercel[.]app/task/windows?token=6df937fe9011

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/linux?flag=4

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/windows?flag=3

  • hxxps://vscodesettingstask.vercel[.]app/api/settings/linux

  • hxxps://vscode-helper171.vercel[.]app/settings/windows?flag=4

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/linux?flag=3

  • hxxps://codeviewer-three.vercel[.]app/task/windows?token=f93a80304111

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/mac?flag=301

  • hxxps://codeviewer-three.vercel[.]app/task/mac?token=2a643f1b401f

  • hxxps://vscode-load.onrender[.]com/settings/mac?flag=5

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/windows?flag=308

  • hxxps://codeviewer-three.vercel[.]app/task/linux?token=f93a80304111

  • hxxps://vscode-load-config.vercel[.]app/settings/windows?flag=4

  • hxxps://vscode-helper-132.vercel[.]app/settings/mac?flag=4

  • hxxps://codeviewer-three.vercel[.]app/task/mac?token=6df937fe9011

  • hxxps://codeviewer-three.vercel[.]app/task/linux?token=6df937fe9011

  • hxxps://vscodesettingstask.vercel[.]app/api/settings/bootstraplinux

  • hxxps://vscode-settings-config.vercel[.]app/settings/mac?flag=9

  • hxxps://vscode-settings-config.vercel[.]app/settings/linux?flag=9

  • hxxps://vscode-helper171.vercel[.]app/settings/mac?flag=4

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/mac?flag=6

  • hxxps://vscodesettings03kui.vercel[.]app/api/settings/windows

  • hxxps://vscode-load-config.vercel[.]app/settings/mac?flag=1

  • hxxps://codeviewer-three.vercel[.]app/task/windows?token=2a643f1b401f

  • hxxps://codeviewer-three.vercel[.]app/task/mac?token=f93a80304111

  • hxxps://vscode-settings-config.vercel[.]app/settings/windows?flag=9

  • hxxps://www.vscodeconfig[.]com/settings/windows?flag=1

  • hxxps://vscode-settings-config.vercel[.]app/settings/mac?flag=606

  • hxxps://vscode-toolkit-bootstrap.vercel[.]app/settings/linux?flag=306

  • hxxps://vscodesettings03kui.vercel[.]app/api/settings/linux

  • hxxps://www.vscodeconfig[.]com/settings/linux?flag=4

  • hxxps://vscode-settings-config.vercel[.]app/settings/windows?flag=606

  • hxxps://vscode-settings-bootstrap.vercel[.]app/settings/linux?flag=305

  • hxxps://www.vscodeconfig[.]com/settings/linux?flag=3

  • hxxps://vscode-helper171-ruby.vercel[.]app/settings/mac?flag=4

  • hxxps://vscodesettingstask.vercel[.]app/api/settings/mac

  • hxxps://codeviewer-three.vercel[.]app/task/linux?token=2a643f1b401f

  • hxxps://vscode-settings-config.vercel[.]app/settings/linux?flag=8

GitHub repository

  • hxxps://github[.]com/veneliteus-dev/casino-game/

  • hxxps://github[.]com/brahmabit/be_challenge_blockchain/

  • hxxps://github[.]com/vnvstore/funtico-labs-assessment-15/

  • hxxps://github[.]com/samuelmeadowbiankah/felina/

  • hxxps://github[.]com/nhonlvsoict/skill-test-main/

  • hxxps://github[.]com/goldendragon68/Bullana/

  • hxxps://github[.]com/ivanwassaf/skill-test/

  • hxxps://github[.]com/SettleMint-Tech-Hub5/SettleMint_Platform/

  • hxxps://github[.]com/veneliteus-dev/exchange-backend/

  • hxxps://github[.]com/0x9x-sketch/Oasis361/

  • hxxps://github[.]com/eastmade/web3project-momo-token/

Appendix C. Search Conditions

Excluded Folders

| list | list |
| --- | --- |
| node_modules | .svg |
| static | .idea |
| license | .lock |
| site-packages | .bin |
| robots | .vscode |
| vendor | .p2 |
| Pods | __MACOSX |
| .git | .angular |
| .github | .yarn |
| .node-gyp | android |
| .nvm .local | cocoapods |
| .cache | homebrew |
| .pyp | xcuserdata |
| .pyi | release |
| .pyenv | debug |
| .qt | x86 |
| .dex | Python |
| __pycache__ | .svn |
| yarn | .android |
| .gradle | cache |
| .cursor | Qt |
| .py | X

caption - Folders Excluded from Search List

Excluded File Extensions

| list | list |
| --- | --- |
| .exe | .mpeg |
| .dll | .m4p |
| .msi | .m4a |
| .dmg | .m4v |
| .vmdk | .aac |
| .iso | .flac |
| .pkg | .aiff |
| .apk | .qt |
| .xapk | .flv |
| .aar | .swf |
| .ap_ | .pyc |
| .aab | .lock |
| .dex | .psd |
| .class | .pack |
| .rpm | .old |
| .deb | .ppt |
| .ipa | .pptx |
| .dsym | .virtualization |
| .mp4 | .indd |
| .avi | .eps |
| .mp3 | .ai |
| .wmv | .a |
| .wma | .jar |
| .mov | .so |
| .webm | .o |
| .avchd | .wt |
| .mkv | .lib |
| .ogg | .dylib |
| .mpe | .bin |
| .mpv | .ffx |
| .svg | .gem |
| .css | .html |
| .scss | X

caption - Extensions Not Uploadable List

autoUploadScript Search String

| list | list |
| --- | --- |
| .keystore | phone |
| database | bank |
| financ | .env |
| env | environment |
| config | configuration |
| configure | .conf |
| .cfg | .ini |
| .properties | .yaml |
| .yml | .toml |
| metamask | phantom |
| bitcoin | ethereum |
| eth | trust |
| wallet | coinbase |
| exodus | ledger |
| trezor | keystore |
| keyring | keychain |
| atomic | electrum |
| mycelium | blockchain |
| bravewallet | rabby |
| coin98 | backpack |
| core | mathwallet |
| solflare | glow |
| keplr | argent |
| martian | petra |
| binance | okx |
| crypto | cryptocurrency |
| hardhat | truffle |
| private | privatekey |
| private_key | private-key |
| privkey | priv_key |
| key | keypair |
| key_pair | key-pair |
| .pem | .p12 |
| .pfx | .jks |
| keystore | .keys |
| keys | .p8 |
| .p7b | .p7c |
| .cer | .crt |
| .cert | cert |
| .der | id_rsa |
| id_dsa | id_ecdsa |
| id_ed25519 | .pub |
| .priv | seed |
| seedphrase | seed_phrase |
| seed-phrase | mnemonic |
| phrase | passphrase |
| pass_phrase | pass-phrase |
| recovery | recoveryphrase |
| recovery_phrase | recovery-phrase |
| backup | backupphrase |
| backup_phrase | backup-phrase |
| 12words | 12_words |
| 12-words | 24words |
| 24_words | 24-words |
| bip39 | bip44 |
| password | passwd |
| pass | pwd |
| credential | credentials |
| auth | authentication |
| token | access_token |
| refresh_token | api_key |
| apikey | api-key |
| apisecret | api_secret |
| api-secret | secret |
| secrets | secretkey |
| secret_key | secret-key |
| masterkey | master_key |
| master-key | masterpassword |
| master_password | master-password |
| account | accounts |
| profile | profiles |
| user | username |
| user_name | user-name |
| login | signin |
| sign_in | sign-in |
| address | addresses |
| tx | transaction |
| transactions | .db |
| .sqlite | .sqlite3 |
| .sql | .mdb |
| .accdb | .dbf |
| .doc | .docx |
| .pdf | .md |
| .markdown | .rtf |
| .odt | .xls |
| .xlsx | .txt |
| text | note |
| notes | memo |
| memos | screenshot |
| screen | snapshot |
| capture | .png |
| .jpg | .jpeg |
| .bmp | .json |
| .js | .ts |
| .jsx | .tsx |
| .csv | .xml |
| .lock | .log |
| .bak | backup |
| .old | .orig |
| .save | .swp |
| .tmp | tmp |
| my | personal |
| vault | safe |
| secure | lock |
| encrypt | decrypt |
| signature | sign |
| certificate | cert |
| identity | session |
| cookie | X

caption - autoUploadScript Search Strings List

ENKI WhiteHat

ENKI WhiteHat

EnkiWhiteHat
EnkiWhiteHat

Offensive security experts delivering deeper security through an attacker's perspective.

Offensive security experts delivering deeper security through an attacker's perspective.

The Beginning of Flawless Security System, From the Expertise of the No.1 White Hacker

Prepare Before a Security Incident Occurs

The Beginning of Flawless Security System, From the Expertise of the No.1 White Hacker

Prepare Before a Security Incident Occurs

The Beginning of Flawless Security System, From the Expertise of the No.1 White Hacker

Prepare Before a Security Incident Occurs

Copyright © 2025. ENKI WhiteHat Co., Ltd. All rights reserved.

Copyright © 2025. ENKI WhiteHat Co., Ltd. All rights reserved.

Copyright © 2025. ENKI WhiteHat Co., Ltd. All rights reserved.