
Bitdefender researchers have discovered a malicious Windsurf IDE (integrated development environment) extension that deploys a multi-stage NodeJS stealer by using the Solana blockchain as the payload infrastructure.
The extension, disguised as an R language support extension for Visual Studio Code, retrieves encrypted JavaScript from blockchain transactions, executes it using NodeJS runtime primitives, drops compiled add-ons to extract Chromium data, all the while establishing persistence with the help of a hidden PowerShell scheduled task.
There’s an official, legitimate extension named REditorSupport, which is likely why the attacker used a very similar name to confuse potential victims.
The attack specifically excludes Russian systems and targets developer environments, enabling threat actors to harvest high-value credentials.
The investigation began after Bitdefender EDR generated multiple detections involving a windsurf.exe on a corporate workstation.
The user had installed a Windsurf extension to assist with R development, an environment comparable to MATLAB. The extension was named:
reditorsupporter.r-vscode-2.8.8-universal
The infection did not rely on a standalone executable. Instead, it operated within the IDE’s trusted extension ecosystem, allowing the malicious logic to persist despite endpoint detections tied to the main application process.
Investigators manually examined the Windsurf extension directory:
.windsurf/
Inside this location, which stores all IDE extensions, they identified the suspicious package. The extension contained a peculiar JavaScript block that decrypted an embedded payload. The code didn’t contain the final malicious functionality directly. Instead, it acted as a loader.
Once decrypted, the payload revealed a second-stage JavaScript component that initiated environmental checks before proceeding further.
The first action of the decrypted payload was to profile the system. It collected the current username and inspected environment variables, along with locale and timezone information, and calculated the UTC time.
The script explicitly searched for Russian indicators. It looked for language markers or “Russian,” compared the system timezone against known Russian regions including Europe/Moscow, Europe/Kaliningrad, Europe/Samara, Asia/Yekaterinburg, Asia/Omsk, Asia/Krasnoyarsk, Asia/Irkutsk, Asia/Yakutsk, Asia/Vladivostok, Asia/Magadan, Asia/Kamchatka, Asia/Anadyr, and MSK, and validated whether the UTC offset fell between +2 and +12.
function _isRussianSystem() {
let isRussianLanguage = [os.userInfo().username, process.env.LANG, process.env.LANGUAGE, process.env.LC_ALL, Intl.DateTimeFormat().resolvedOptions().locale].some(info => info && /ru_RU|ru-RU|Russian|russian/i.test(info)),
timezoneInfo = [Intl.DateTimeFormat().resolvedOptions().timeZone, new Date().toString()],
russianTimezones = ["Europe/Moscow", "Europe/Kaliningrad", "Europe/Samara", "Asia/Yekaterinburg", "Asia/Omsk",
"Asia/Krasnoyarsk", "Asia/Irkutsk", "Asia/Yakutsk", "Asia/Vladivostok", "Asia/Magadan", "Asia/Kamchatka", "Asia/Anadyr", "MSK"
],
isRussianTimezone = timezoneInfo.some(info => info && russianTimezones.some(tz => info.toLowerCase().includes(tz.toLowerCase()))),
utcOffset = -new Date().getTimezoneOffset() / 60,
isRussianOffset = utcOffset >= 2 && utcOffset <= 12;
return isRussianLanguage && (isRussianTimezone || isRussianOffset)
}
name(_isRussianSystem, "_isRussianSystem");
If the system matched these criteria, execution stopped immediately.
This deliberate exclusion of Russian systems indicates operational safeguards typically associated with financially motivated cybercrime groups seeking to avoid domestic scrutiny.
Because the extension runs within a NodeJS environment and is not sandboxed, it can freely interact with the operating system and network stack.
After passing system profiling checks, the malware initiated POST requests to:
https://api.mainnet-beta.solana[.]com
It invoked the Solana JSON-RPC method:
getSignaturesForAddress
Instead of contacting a traditional command-and-control (C2) server, the malware used Solana as decentralized infrastructure. It queried blockchain transactions and retrieved encoded data embedded within transaction metadata.
When the request was completed, the malware received buffers containing JavaScript payload fragments. It decoded and prepared them for execution.
The retrieved content consisted of base64-encoded JavaScript layered with AES-encrypted payload components. The loader reconstructed the malicious runtime dynamically.

Because Windsurf extensions operate in a NodeJS environment without strict sandbox isolation, the malware gained direct filesystem access and could load native modules without restriction.

After dynamic execution, the malware dropped files into:
AppData\Local\Temp\<random_string>\
Observed files included:
These files are DLLs and are loaded by NodeJS as .node files.
const addon = require('C:/Users/<USER>/AppData/Local/Temp/<Random_String>/c_x64.node');
const result = addon.extractBrowserData(browser, outputFile, showAll, decryptedData, profile);
The researcher confirmed that these components function as credential stealers.
These native modules enable:
After deploying the native stealer modules, the malware invoked PowerShell to achieve persistence.
The PowerShell component hid its console window, leveraged Win32 API calls through Add-Type, and created a scheduled task named:
UpdateApp
The task executed:

It configured the task to run at startup with the highest privileges and bypass execution policy restrictions.
The script also interacted with the following registry entry and removed evidence that it exists:
HKCU:\Software\Microsoft\Windows\CurrentVersion\Run
It removed registry entries matching specific execution patterns and re-established persistence mechanisms.
This ensured that even if the IDE closed, the malicious workflow continued.
As a final step in establishing persistence, the script launched:
C:\Users\<user>\AppData\Roaming\node_x86\node\node.exe
with:
C:\Users\<user>\AppData\Roaming\zplnUtG\index.js
The infection became self-sustaining across system reboots.
→ Download Windsurf Extension
→ Run Malicious NodeJS Package
→ PowerShell execution
→ Scheduled Task creation (persistence)
→ Base64 JavaScript
→ AES-encrypted payload
→ Dynamic execution
→ Remote retrieval from Solana
→ Browser interaction via native .node DLLs
This incident reveals how attackers increasingly embed themselves inside trusted development tools rather than relying on traditional delivery methods.
By disguising a credential-stealing operation as a seemingly legitimate R extension, the operators gained execution inside a developer’s IDE, retrieved encrypted payloads from the Solana blockchain, and deployed native modules capable of extracting sensitive browser data.
The deliberate exclusion of Russian systems further suggests a financially motivated campaign built with operational safeguards.
tags
Raul Bucur is the technical leader of a small team of security researchers. He's passionate about technology, malware reverse engineering, malware detection and forensics analysis.
View all postsSilviu is a seasoned writer who's been following the technology world for more than two decades, covering topics ranging from software to hardware and everything in between.
View all posts