GlassWorm: 9 Infected VS Code Extensions Are Still Live -- Inside the Rust-Powered Supply Chain Attack Targeting Developers
TL;DR
A supply chain campaign called GlassWorm has compromised at least 12 VS Code extensions with a Rust-compiled, fileless PE loader that executes arbitrary Windows binaries entirely in-memory using direct NT API calls to bypass EDR. As of March 16, 2026, nine of the twelve infected extensions remain live on the Microsoft Visual Studio Marketplace. If you are a developer using VS Code on Windows, check your installed extensions against the IOC list below immediately.
The Situation
Sometime in October 2025, a threat actor began poisoning the VS Code extension ecosystem. Twelve extensions -- spanning themes, Git utilities, syntax highlighters, and even an AI coding assistant clone -- were either hijacked or published as lookalikes, each carrying a silent backdoor. That backdoor steals GitHub tokens, npm credentials, and OpenVSX access tokens. It activates a SOCKS5 proxy on the infected machine. It phones home over Solana blockchain RPC and Google Calendar API. And it delivers a second-stage payload: a Rust-compiled native Node.js addon that can load and execute any Windows PE binary entirely in memory, with zero disk writes, using direct NT API syscalls that most EDR products do not hook.
Community researchers flagged the campaign within weeks. Cleanup scripts were published. A scanner was built. Three of the twelve extensions were removed from the marketplace.
The other nine are still there. Five months later.
This is not a retrospective. This is an active threat.
Why Developers Are High-Value Targets
The targeting here is precise and intentional. Software developers are not random victims -- they are access multipliers. A single compromised developer workstation can yield:
- GitHub personal access tokens with push rights to production repositories
- npm publish tokens capable of injecting malicious code into packages consumed by thousands of downstream projects
- CI/CD pipeline credentials (AWS, GCP, Azure service accounts) stored in environment variables or
.envfiles - SSH keys with access to production infrastructure
- Code signing certificates that can legitimize future malicious payloads
The worm component of GlassWorm exploits this access directly. Once a developer is infected, their stolen credentials are used to inject malicious code into their own repositories and packages -- spreading the infection to every downstream consumer. This is the "Glass" in GlassWorm: the propagation is transparent, invisible to the developer whose identity is being weaponized.
The Infected Extensions
The following VS Code extensions have been confirmed as compromised. Nine remain available for installation on the Microsoft Visual Studio Marketplace as of March 16, 2026.
| Extension ID | Category | Marketplace Status |
|---|---|---|
codejoy.codejoy-vscode-extension | Productivity | LIVE -- MALICIOUS |
l-igh-t.vscode-theme-seti-folder | Theme | LIVE -- MALICIOUS |
kleinesfilmroellchen.serenity-dsl-syntaxhighlight | Syntax | LIVE -- MALICIOUS |
JScearcy.rust-doc-viewer | Documentation | LIVE -- MALICIOUS |
SIRILMP.dark-theme-sm | Theme | LIVE -- MALICIOUS |
CodeInKlingon.git-worktree-menu | Git | LIVE -- MALICIOUS |
ginfuru.better-nunjucks | Syntax | LIVE -- MALICIOUS |
jeronimoekerdt.color-picker-universal | Utility | LIVE -- MALICIOUS |
srcery-colors.srcery-colors | Theme | LIVE -- MALICIOUS |
ellacrity.recoil | -- | Removed (404) |
grrrck.positron-plus-1-e | -- | Removed (404) |
cline-ai-main.cline-ai-agent | AI Assistant | Removed (404) |
Note the breadth of categories. This is not a narrow campaign hoping a specific type of developer installs a specific type of tool. It is a wide net: themes that any developer might grab for aesthetics, a Rust documentation viewer targeting the Rust ecosystem specifically, a Git worktree manager for advanced Git users, a Nunjucks template highlighter for web developers, and a fake Cline AI agent targeting developers interested in AI-assisted coding. The actor is maximizing surface area.
The Loader: Anatomy of a Fileless PE Executor
The sample at the core of this analysis is index_x64_decrypted.node -- the decrypted second stage that GlassWorm delivers to compromised machines. It is a PE32+ DLL compiled in Rust, disguised as a Node.js native addon.
Sample Metadata
| Field | Value |
|---|---|
| SHA256 | de81eacd045a88598f16680ce01bf99837b1d8170c7fc38a18747ef10e930776 |
| SHA1 | acb46155adabd85a833e135e5f983bf395b0804a |
| MD5 | 0f59b6a1c325318f10be0b68f3ba0687 |
| File Type | PE32+ DLL (x86-64), Windows GUI subsystem |
| File Size | 175,616 bytes |
| Compile Time | 2025-11-19 12:27:00 UTC |
| Compiler | Rust 1.83.0 (rustc ed61e7d7e242494fb7057f2657300d9e77bb4fcb) |
| Original Name | generate.dll (from PDB path: generate.pdb) |
The file exports a single symbol: napi_register_module_v1 -- the standard initialization function that Node.js calls when loading any .node native addon via require(). This is the entry point.
The Neon + memexec Architecture
The loader is built on two Rust crates:
- Neon 1.0.0 -- A framework for writing safe, fast native Node.js modules in Rust using the N-API interface. Neon handles the JavaScript-to-Rust bridge, allowing the malware to expose a clean JavaScript API.
- memexec 0.2.0 -- A Rust crate that implements reflective PE loading. It parses PE headers, maps sections into memory, resolves imports, applies relocations, and calls the entry point -- all without writing a file to disk.
When loaded, the module registers a single JavaScript function called run that accepts a Buffer containing a raw Windows PE binary:
// This is how the GlassWorm orchestrator invokes the loader
const loader = require('./index_x64_decrypted.node');
loader.run(peBuffer); // peBuffer = stage 3 payload as a Node.js Buffer
When run() is called, the Rust code at 0x1800056FF executes the following sequence:
- Retrieve the JavaScript
Bufferargument via N-API - Extract the raw byte pointer and length
- Pass the bytes to
memexec::exec(), which:- Parses MZ and NT headers, validates PE signature
- Calls
NtAllocateVirtualMemory(fromntdll.dll) to allocate RWX memory - Copies PE sections into the allocated region
- Applies base relocations
- Resolves imports via
LoadLibraryA/GetProcAddress - Calls
NtProtectVirtualMemoryto set final section permissions - Transfers execution to the PE entry point
- The stage 3 payload is now running inside the
node.exeprocess
Why Direct NT API Calls Matter
This is the critical evasion technique. Most EDR products hook user-mode Win32 API functions like VirtualAlloc and VirtualProtect in kernel32.dll to detect memory manipulation consistent with code injection or reflective loading. GlassWorm bypasses this entirely by importing NtAllocateVirtualMemory and NtProtectVirtualMemory directly from ntdll.dll -- the lowest user-mode layer before the kernel syscall interface.
From the import table:
ntdll.dll:
- NtWriteFile
- RtlNtStatusToDosError
- NtAllocateVirtualMemory <-- direct syscall wrapper
- NtProtectVirtualMemory <-- direct syscall wrapper
EDR hooks on kernel32!VirtualAlloc and kernel32!VirtualProtect are never triggered. The memory allocation and permission changes happen below the hook layer. Combined with the fact that the loaded PE never touches disk, this creates a detection gap that many endpoint security products will miss entirely.
Error Strings Confirm Reflective Loader Capabilities
The binary contains unstripped error strings from the memexec crate that confirm the full reflective loading pipeline:
PeParserErr -- PE parsing failures
PeLoaderErr -- PE loading failures
LoadLibararyFail -- Import resolution failed (note: typo preserved from crate)
GetProcAddressFail -- Import function lookup failed
NtAllocVmErr -- NtAllocateVirtualMemory call failed
NtProtectVmErr -- NtProtectVirtualMemory call failed
MismatchedArch -- x86/x64 architecture mismatch
UnsupportedDotNetExecutable -- .NET binaries explicitly rejected (native PE only)
InvalidDosSignature -- Bad MZ header
InvalidNtSignature -- Bad PE signature
NoEntryPoint -- PE has no entry point to call
The UnsupportedDotNetExecutable error is notable -- it tells us the actor specifically tested against .NET binaries and the loader is designed exclusively for native PE payloads. The MismatchedArch error combined with the _x64 filename convention strongly suggests that arm64 and ia32 variants exist for cross-architecture coverage.
The Kill Chain
[1] Developer installs infected VS Code extension from Marketplace
|
v
[2] Extension activates silently on VS Code launch
- Steals: GITHUB_TOKEN, .npmrc, PAT, accessToken
- Activates SOCKS5 proxy on developer machine
- Injects Unicode steganography into source files
|
v
[3] Extension contacts C2 via trusted service abuse:
- Solana mainnet-beta RPC (blockchain reads)
- Google Calendar API (event field data)
- IPFS / Pastebin / raw.githubusercontent.com
|
v
[4] C2 delivers encrypted payload: index_x64.node
- Decrypted at runtime by JavaScript orchestrator
- Loaded via require() as Node.js native addon
|
v
[5] Loader (this sample) receives stage 3 PE via run(Buffer)
- NtAllocateVirtualMemory -> map sections -> resolve imports
- NtProtectVirtualMemory -> set page permissions
- Execute PE entry point in-process
|
v
[6] Stage 3 payload runs inside node.exe / VS Code process
- Infostealer, RAT, or backdoor (variant-dependent)
- Process appears as legitimate developer tooling
|
v
[7] Worm propagation via stolen developer credentials
- Publishes backdoored updates to victim's own extensions
- Injects malicious code into victim's npm packages
- Exponential spread through developer trust chains
The worm propagation at stage 7 is what makes this campaign particularly dangerous. Each infected developer becomes an unwitting distribution node. Their colleagues trust their extensions and packages. Their CI/CD pipelines auto-install updates. The supply chain attack feeds itself.
C2 Infrastructure: Hiding in Plain Sight
GlassWorm's C2 architecture is designed to be invisible on corporate networks by abusing services that developers use daily.
Solana Blockchain RPC
The extensions contain references to Solana's mainnet-beta RPC endpoints. This is a technique we have seen in increasingly sophisticated campaigns: the threat actor writes C2 configuration data to the Solana blockchain (or reads from a known account address), and the malware retrieves it via standard RPC calls. On a network where developers are building DeFi applications or using Web3 tooling, Solana RPC traffic is expected. There is no malicious domain to block. The "C2 server" is the blockchain itself.
Google Calendar API
The extensions also reference googleapis.com/calendar endpoints. Google Calendar event descriptions and custom fields can store arbitrary text -- including C2 commands, configuration updates, or payload URLs. The traffic goes to a Google domain over HTTPS. It looks identical to a developer's calendar syncing. Network-level detection is nearly impossible without deep content inspection of authenticated Google API traffic.
Supplementary Channels
Additional C2 and payload delivery channels include IPFS (decentralized, no single takedown point), Pastebin (ubiquitous, frequently allowlisted), raw.githubusercontent.com (trusted CDN, used by every developer), and various tunneling services for dynamic C2 addressing.
Build Artifacts and Actor Fingerprinting
The threat actor compiled this loader on a Windows machine using the Administrator account. The Rust build environment left recoverable artifacts in the binary:
C:\Users\Administrator\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\memexec-0.2.0\src\peparser\pe.rs
C:\Users\Administrator\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\neon-1.0.0\src\types_impl\mod.rs
Key observations:
- Build user:
Administratoron a dedicated Windows build VM - Crates.io registry hash:
1949cf8c6b5b557f-- this value is derived from the local Cargo registry snapshot and is shared across all binaries built from the same environment. It is a clustering pivot: any other sample containing this hash was built on the same machine or from the same Cargo cache. - Rust 1.83.0 (released 2024-11-28) -- the actor was using a recent stable toolchain at compile time
- PDB path:
generate.pdb-- the original project was named "generate," which may correlate to npm packages or GitHub repositories using that name - Compile timestamp:
0x691DB794= 2025-11-19 12:27:00 UTC -- approximately four weeks after the VS Code campaign began in October 2025, suggesting iterative development
These are OPSEC failures. The actor did not strip debug symbols, did not falsify the compilation timestamp, and did not sanitize build paths. The crates.io hash alone enables clustering of every binary built from this development environment.
MITRE ATT&CK Mapping
| Tactic | Technique | ID | Application in GlassWorm |
|---|---|---|---|
| Initial Access | Supply Chain Compromise: Software Supply Chain | T1195.002 | Compromised VS Code extensions and npm packages |
| Execution | JavaScript | T1059.007 | Extension JS activates on VS Code launch; npm postinstall triggers |
| Defense Evasion | Reflective Code Loading | T1620 | memexec loads PE entirely in-memory |
| Defense Evasion | Native API | T1106 | Direct NtAllocateVirtualMemory / NtProtectVirtualMemory calls |
| Defense Evasion | Impair Defenses | T1562.001 | NT API calls bypass EDR hooks on kernel32 equivalents |
| Defense Evasion | Obfuscated Files | T1027 | Encrypted .node file on disk; Unicode steganography in source |
| Defense Evasion | Deobfuscate/Decode | T1140 | Runtime decryption of loader before execution |
| Persistence | Process Injection | T1055 | In-process PE loading within node.exe / VS Code |
| Credential Access | Steal Application Access Token | T1528 | Harvests GitHub, npm, OpenVSX tokens |
| Command and Control | Web Service | T1102 | Solana blockchain RPC, Google Calendar API |
| Command and Control | Proxy: Internal Proxy | T1090.001 | SOCKS5 proxy activated on developer machines |
| Lateral Movement | Supply Chain Compromise | T1195.002 | Worm propagation via stolen developer publishing credentials |
IOC Summary
File Indicators
SHA256: de81eacd045a88598f16680ce01bf99837b1d8170c7fc38a18747ef10e930776
SHA1: acb46155adabd85a833e135e5f983bf395b0804a
MD5: 0f59b6a1c325318f10be0b68f3ba0687
Filenames:
index_x64_decrypted.node (decrypted loader)
index_x64.node (encrypted on-disk variant)
generate.dll (original compiled name)
generate.pdb (PDB debug artifact)
Build Artifact Indicators
Build Path: C:\Users\Administrator\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\
Crates.io Hash: 1949cf8c6b5b557f
Rustc Commit: ed61e7d7e242494fb7057f2657300d9e77bb4fcb
Rust Version: 1.83.0
Neon Version: 1.0.0
memexec Version: 0.2.0
Compile Time: 0x691DB794 (2025-11-19 12:27:00 UTC)
Behavioral Indicators
NT API Imports: NtAllocateVirtualMemory, NtProtectVirtualMemory (from ntdll.dll)
Win32 API: CreateMutexA (execution guard)
N-API Export: napi_register_module_v1
JS Function: run(Buffer)
Rust Module: generate
Mutex: Local\RustBacktraceMutex00000000
Network IOC Patterns
C2 Patterns in Extension JavaScript:
- solana|mainnet-beta|rpc (blockchain C2)
- googleapis[.]com/calendar (covert channel)
- raw[.]githubusercontent[.]com (payload delivery)
- ipfs (decentralized delivery)
- pastebin[.]com (config delivery)
Infected VS Code Extension IDs
STILL LIVE (as of 2026-03-16):
codejoy.codejoy-vscode-extension
l-igh-t.vscode-theme-seti-folder
kleinesfilmroellchen.serenity-dsl-syntaxhighlight
JScearcy.rust-doc-viewer
SIRILMP.dark-theme-sm
CodeInKlingon.git-worktree-menu
ginfuru.better-nunjucks
jeronimoekerdt.color-picker-universal
srcery-colors.srcery-colors
REMOVED:
ellacrity.recoil
grrrck.positron-plus-1-e
cline-ai-main.cline-ai-agent
Detection Guidance
YARA Rule
rule GlassWorm_Neon_MemExec_Loader {
meta:
author = "GHOST - Breakglass Intelligence"
date = "2026-03-16"
description = "Detects GlassWorm Rust/Neon reflective PE loader using memexec crate"
hash = "de81eacd045a88598f16680ce01bf99837b1d8170c7fc38a18747ef10e930776"
tlp = "WHITE"
reference = "https://intel.breakglass.tech"
strings:
$neon1 = "napi_register_module_v1" ascii
$memexec1 = "NtAllocVmErr" ascii
$memexec2 = "NtProtectVmErr" ascii
$memexec3 = "PeParserErr" ascii
$memexec4 = "PeLoaderErr" ascii
$memexec5 = "LoadLibararyFail" ascii // note: typo from crate
$memexec6 = "MismatchedArch" ascii
$memexec7 = "UnsupportedDotNetExecutable" ascii
$memexec8 = "NoEntryPoint" ascii
$rust_build = "index.crates.io-" ascii
$module_name = "generate::run" ascii
condition:
uint16(0) == 0x5A4D and
filesize < 500KB and
$neon1 and
3 of ($memexec*) and
($rust_build or $module_name)
}
Suricata Rules
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"BGI - Possible GlassWorm C2 - VS Code/Node to Solana RPC";
flow:established,to_server;
content:"mainnet-beta"; http_uri;
content:"solana"; http_host;
metadata:created_at 2026_03_16;
reference:url,intel.breakglass.tech;
classtype:trojan-activity;
sid:9000101; rev:1;
)
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"BGI - Possible GlassWorm C2 - Node Process to Google Calendar API";
flow:established,to_server;
content:"googleapis.com"; http_host;
content:"/calendar"; http_uri;
metadata:created_at 2026_03_16;
reference:url,intel.breakglass.tech;
classtype:trojan-activity;
sid:9000102; rev:1;
)
EDR Detection Logic
For endpoint detection teams, the highest-fidelity signal is:
-
Process
node.exeorcode.execallingNtAllocateVirtualMemorywithPAGE_EXECUTE_READWRITEprotection followed by execution transfer to the newly allocated region. This is the reflective loading sequence. Legitimate Node.js native addons allocate memory but almost never request executable permissions via direct NT API calls. -
Any
.nodefile in anode_modulesdirectory that imports fromntdll.dll. Legitimate native addons import fromkernel32.dll,ucrtbase.dll, and theapi-ms-win-*shim DLLs. Directntdll.dllimports in a Node.js addon are a strong anomaly signal. -
VS Code extension directories containing
.nodefiles with PE characteristics (MZ header) that were not present in the original extension manifest or are not from well-known native addon packages (e.g.,node-pty,nsfw,sqlite3).
Network Detection
- Block or alert on
node.exe/code.exeprocesses connecting to Solana RPC endpoints (api.mainnet-beta.solana.com,mainnet.helius-rpc.com, and similar) - Alert on
node.exe/code.exemaking authenticated requests togoogleapis.com/calendaroutside of expected calendar integration applications - Monitor for
.nodefile downloads from npm registry that contain PE headers
Source Code Integrity
Scan developer repositories for Unicode variation selectors (U+FE00 through U+FE0F) injected between code characters. GlassWorm uses Unicode steganography to embed hidden data in source files that appears invisible in editors and code review tools but can be read programmatically by the malware. A simple detection:
# Find files containing Unicode variation selectors (GlassWorm steganography)
grep -rP '[\x{FE00}-\x{FE0F}]' --include='*.js' --include='*.ts' --include='*.json' .
So What? -- Why This Matters Right Now
This is not a historical analysis of a remediated threat. This is an ongoing supply chain compromise with active distribution channels.
Nine malicious VS Code extensions are live on the Microsoft marketplace right now. Every developer who installs one of them gets their GitHub tokens, npm credentials, and cloud API keys stolen. Their machine becomes a SOCKS5 proxy node. Their own repositories and packages become distribution vectors for the next wave of infections. And they receive a fileless PE loader that executes arbitrary malware inside their Node.js process, below the detection threshold of most endpoint security products.
The technical sophistication is real -- Rust, Neon N-API bindings, direct NT API syscalls, blockchain C2, Google Calendar covert channels -- but the most dangerous aspect is the worm propagation model. This is a supply chain attack that builds its own supply chain. Every compromised developer extends the blast radius.
If you are a defender:
- Check every developer workstation in your organization against the extension list above. Today.
- Rotate all GitHub tokens, npm tokens, and cloud credentials on any machine where an infected extension was installed.
- Audit your npm packages for unexpected
.nodefiles containing PE headers. - Deploy the YARA rule above to hunt for the loader in your environment.
- Report the nine live extensions to Microsoft via the VS Code Marketplace "Report Abuse" mechanism.
If you are Microsoft:
- These extensions were flagged by community researchers in October 2025. It is now March 2026. Nine of twelve remain live. The marketplace review process has a gap, and developers are paying for it.
If you are the threat actor:
- You left your build paths in the binary. You left the PDB name. You left the compile timestamp. You left the crates.io registry hash. We are clustering everything you have ever built from that Cargo environment. The investigation is not over.
Timeline
| Date | Event |
|---|---|
| October 2025 | GlassWorm campaign begins; 12+ VS Code extensions compromised |
| 2025-10-27 | Community detection by Sebastian Broers / ConbroIT Security (Munich) |
| 2025-11-19 | PE loader compiled (this sample): generate.dll built by Administrator |
| 2025-12-08 | Community scanner glassworm-scanner published |
| 2026-03-16 | Sample submitted to threat intelligence platform |
| 2026-03-16 | Breakglass analysis confirms 9/12 extensions still live on marketplace |
References
- GitHub:
natorus87/vscode-extension-cleanup-glassworm-- Extension list, cleanup scripts, campaign documentation - GitHub:
cahyod/glassworm-scanner-- Detection signatures, C2 pattern identification - ConbroIT Security (Munich, Germany) -- Initial community response and incident handling
- Rust crate
memexec0.2.0 -- Reflective PE loader library (legitimate crate, abused by actor) - Rust crate
neon1.0.0 -- Node.js native addon framework (legitimate crate, abused by actor)
Analysis by GHOST -- Breakglass Intelligence Published: 2026-03-16 TLP:WHITE -- Unrestricted distribution