72 Extensions Later: GlassWorm's Open VSX Supply Chain Pivot
Has anyone dug into the latest GlassWorm write-up on The Hacker News? The shift from direct malicious uploads to abusing the dependency graph in the Open VSX registry is a significant escalation.
The threat actors are essentially using 'clean' extensions as trojans that pull in malicious payloads via extensionDependencies or extensionPack. This complicates static analysis significantly because if you're just reviewing the main entry point of an extension, you'll miss the loader entirely.
For those auditing your developers' environments, you can't just verify the publisher of the installed package anymore. You need to recursively check the package. files of all dependencies to see what they are actually pulling down.
Here is a quick Python snippet I whipped up to recursively resolve dependencies from a local extension manifest to spot suspicious transitive pulls:
import
def check_dependencies(manifest_path):
with open(manifest_path, 'r') as f:
data = .load(f)
# Check for extensionPack (bundled extensions)
packs = data.get('extensionPack', [])
if packs:
print(f"[!] Bundled ExtensionPack found: {packs}")
# Check for extensionDependencies
deps = data.get('extensionDependencies', {})
if deps:
print(f"[!] ExtensionDependencies found: {deps}")
return packs + list(deps.keys())
# Usage: check_dependencies('path/to/extension/package.')
With 72 flagged extensions in the wild acting as nodes in this attack graph, how are you handling extension governance in your org? Are you blocking Open VSX entirely, or do you have a vetting process for these dependency chains?
From a SOC perspective, this is a nightmare to signature because the initial file looks legitimate. We are pivoting to behavioral detection. We are looking for VS Code spawning unusual child processes, which shouldn't happen during standard development tasks.
Here is the KQL query we are testing in Sentinel to catch the execution phase:
DeviceProcessEvents
| where InitiatingProcessFileName == "Code.exe"
| where FileName in~ ("powershell.exe", "cmd.exe", "bash", "wscript.exe")
| where ProcessCommandLine !contains "git"
| project Timestamp, DeviceName, AccountName, ProcessCommandLine
It's noisy if devs use terminals heavily, but the GlassWorm loaders usually trigger specific obfuscation patterns we can filter on.
We've completely disabled the Open VSX registry on our build boxes via proxy. It's too much risk compared to the value of random extensions.
If you need to lock this down without a proxy, you can modify the VS Code settings. to ignore specific extension recommendations or disable the marketplace entirely:
{ "extensions.showRecommendationsOnlyOnDemand": true, "extensions.autoUpdate": false }
However, the real fix is an internal proxy that only mirrors extensions after a manual security review. Trusting a transitive dependency from a public registry is basically gambling with your source code.
I analyzed one of the "helper" extensions involved in this campaign. It's crazy how minimal the actual malicious code is. It's basically just a wrapper that reaches out to a C2 server to fetch the next stage.
The use of extensionPack is the clever part here because it forces the installation of the malicious payload immediately upon installing the 'safe' package. Most devs don't even realize they just installed 3 other extensions alongside the one they wanted.
That wrapper technique is insidious. For those who can't block the registry entirely, validating the dependency graph before install is a solid middle ground. You can unpack the VSIX and inspect the manifest programmatically to flag any non-whitelisted dependencies.
import
manifest = .load(open('extension/package.'))
print(manifest.get('extensionDependencies', []))
This helps expose the trojan horse before execution.
Verified Access Required
To maintain the integrity of our intelligence feeds, only verified partners and security professionals can post replies.
Request Access