CodeRelay is the name we gave to a coordinated campaign involving 13 malicious VSIX packages across 12 VS Code extensions. Most look like compiler, code-runner, or “timeline” tools, but their code is designed to send developer chat data to external LLM services. This report is based on static analysis only: we did not install or run the extensions, and we did not observe any live network requests.
Ten of the twelve extension identities hide the relay logic inside a compressed payload decoded at runtime (Family A). Most are presented as “compiler,” “code runner,” or “timeline” developer tools. The other two — Search Code Ultra and Search Code Fast — ship the same relay logic as plain, readable JavaScript (Family B).
Across both families, the code is written so that a user's chat text, pasted code, and prior conversation history are sent to one of three external endpoints using an API key embedded in the extension; image attachments are relayed only in the variants that support that feature. Five of the twelve display names additionally use Unicode homoglyphs or invisible characters — a Cyrillic letter standing in for a Latin one, or a zero-width character appended to a name — so the extension looks like an ordinary compiler tool at a glance.
A monitoring feed flagged two unrelated-looking extensions — a chat assistant and a “Java compiler assistant” — sharing the same unusual pattern: decoding and executing a hidden payload from a bundled binary at runtime. Searching for other listings with that same structural fingerprint, rather than by name or publisher, grew the set from 2 samples to 12 extension identities across at least nine Marketplace publisher accounts.
Workflow reconstructed through static analysis of the collected VSIX packages.
Family A (10 identities): a small, unobfuscated extension.js reads a second file, extension.bin, XORs every byte with 0xAA, decompresses the result (zlib or brotli), and runs it with new Function():
const decoded = zlib.inflateSync(
fs.readFileSync(__dirname + '/extension.bin').map(b => b ^ 170)
).toString();
new Function('exports', 'require', 'module', '__filename', '__dirname', decoded)(
exports, require, module, __filename, __dirname
);
Three of the ten Family A samples use brotli instead of zlib; two go a step further and store their endpoint and key as base64-encoded strings rather than plain literals, decoded at runtime — the same infrastructure, with an extra layer of string-matching evasion.
Family B (2 identities): Pstudio.search-code-ultra and Ptudios.search-code-fast do not use the encoded payload and ship the same relay logic as plain JavaScript, API key inline.
Most variants gate the chat panel behind a hardcoded password recoverable from the decoded source; two CPLUSPLUS builds have no check at all. Once unlocked, the code is designed to send the user's chat text, pasted code, and prior conversation history to a hardcoded endpoint. Image attachments are relayed only in the variants that support that feature — confirmed absent in Search Code Ultra 0.2.6, and not independently re-verified per sample beyond that.
Several nominally unrelated publisher accounts share hardcoded passwords, API keys, and endpoint domains verbatim. Passwords cluster by theme, not by publisher: the two C/C++-themed extensions (from PTIT and Viettel) share one password, and the two Java-themed extensions from those same two accounts share a different, matching password — evidence the samples come from a common template rather than independent developers.
VNPT.vcr-runner and dsanms.dsanms go further, sharing a byte-for-byte identical password-check function, the same endpoint, the same API key, and the same message-limit logic — strong evidence of a common codebase. The two use the same reinstall-lock logic under different filenames, and VNPT.vcr-runner's webview code still hardcodes the label “DSANMS”, further evidence of a shared codebase. Pstudio.search-code-ultra and Ptudios.search-code-fast separately declare the same source-repository reference (github.com/haquan/Extension-X) in their manifests.
Together this is strong evidence of a shared operator or build pipeline — not proof of a single named actor. Three publisher accounts borrow the names of real Vietnamese telecom and education institutions (Viettel, VNPT, PTIT); we found no evidence tying those organizations to this activity. modelgate.top is one endpoint the relay code is configured to contact — it is a service used by some samples, not a confirmed campaign operator.
Both CPLUSPLUS extensions bundle a Windows-only Python script, mouse_monitor.py, spawned as a detached process on activation. It polls the cursor position and foreground window title roughly every 50 milliseconds and, when the cursor lingers over the extension's own sidebar icon, prints a local signal used to auto-focus its panel. Static analysis found no network calls or behavior beyond this local auto-focus mechanism.
VNPT.vcr-runner 0.0.1 and dsanms.dsanms use identical reinstall-lock logic, written outside the extension's install directory so it may remain after uninstall, to enforce a six-messages-per-twenty-minutes free-tier chat limit. The filename differs: dsanms.dsanms uses ~/.dsanms_lock, while VNPT.vcr-runner 0.0.1 uses ~/.vnpt_code_runner_lock. This is a state-tracking artifact, not a code-execution persistence mechanism — nothing in either extension regains code execution from this file on its own.
13 confirmed malicious VSIX packages, representing 12 unique extension identities.
| Publisher | Extension | Version | Family | AgentMesh link |
|---|---|---|---|---|
| KakaStudio | kaka-chat (KaKa Chat) | 0.0.1 | A | AgentMesh report |
| GHT | java-compiler (JAVA Compiler Assistant) | 0.0.1 | A | AgentMesh report |
| CPLUSPLUS | cpp-compiler-provider (С⁄С++, homoglyph) | 0.0.5 | A | AgentMesh report |
| CPLUSPLUS | java-compiler-provider (JAVA, hidden Unicode) | 0.0.5 | A | AgentMesh report |
| PTIT | ptit-cpp-timeline (Ⅽ∕С++, homoglyph) | 0.1.1, 0.1.2 | A | AgentMesh report |
| PTIT | ptit-java-timeline (Ј А Ѵ А, homoglyph) | 0.1.2 | A | AgentMesh report |
| VNPT | vcr-runner (VCR Code Runner) | 0.0.1 | A | AgentMesh report |
| Viettel | vcc-cpp-tools (VCC C/C++ Compiler) | 0.0.3 | A | AgentMesh report |
| Viettel | vjc-java-pack (VJC Java Compiler) | 0.0.3 | A | AgentMesh report |
| dsanms | dsanms (С∕С++ Сοмрliеr Assistant, homoglyph) | 0.1.3 | A | AgentMesh report |
| Pstudio | search-code-ultra (Search Code Ultra) | 0.2.6 | B | AgentMesh report |
| Ptudios | search-code-fast (Search Code Fast) | 0.1.2 | B | AgentMesh report |
Limitation: this research is static-analysis only. No extension was installed, executed, or allowed to make a network request; findings describe what the code is written to do, not observed runtime or downstream behavior.
| Domain | Note |
|---|---|
| modelgate[.]top | Operator/identity not confirmed; one of several endpoints used by the malicious samples, not a confirmed campaign operator |
| platform.beeknoee[.]com | Endpoint contacted by multiple samples; operator and other uses not independently confirmed by this research |
| jeniya[.]top | Endpoint contacted by one variant only; operator and other uses not independently confirmed by this research |
Redacted key fingerprints (full values withheld):
| Redacted key | Endpoint | SHA-256 of full key |
|---|---|---|
| sk-dc158a6...d9ff | modelgate[.]top | 549da52ad222697053d25d82c34f03d2bc8b02afa6e8c41e6e1e9d82dcf78569 |
| sk-bee-f0d...b332 | platform.beeknoee[.]com | 4916dd025518028ac019d62b223ab569ae4ec7eb29d205c66c00a3a67dac10de |
| sk-dbe7d37...8f1a | modelgate[.]top | 1b5972b9a152100f0e9735cf1ff89ae0d66e4db44837a3b33e66ae9b9d1d01a4 |
| sk-bee-4da...627f | platform.beeknoee[.]com | 3aa6d1b7a231b181a106045b8296ae17e9656b2c96c5727d723f419afbfba675 |
| sk-ILl2oKk...Xtp4 | jeniya[.]top | 5edab8c15d0eb5792871475a72b371b4f5c3042d9edb0e2094206d8baecb1819 |
VSIX hashes (SHA-256) — 13 confirmed malicious packages:
| Publisher.id | Version | VSIX SHA-256 |
|---|---|---|
| KakaStudio.kaka-chat | 0.0.1 | eac26d03dad0ab5bfef3685bdfbdd9bbabc3fe59b1f3c4c63d3dcb7ddb67279d |
| GHT.java-compiler | 0.0.1 | 7e361cd84e8a992956abf8dd7f7835cd87b879a941681aff1a2e6ccb3d451a2a |
| CPLUSPLUS.cpp-compiler-provider | 0.0.5 | 8d85fe98e75fd2ac21fe6d56f38a2e0d78cd42369c51a75e94fefa7cfa5636bf |
| CPLUSPLUS.java-compiler-provider | 0.0.5 | 7ce6145dd72035c073cf4a12854d3f21c48cf1dbf68cd1d17cc8164938aae348 |
| PTIT.ptit-cpp-timeline | 0.1.1 | 8fba2af7ef20a22241fbbcb9af5446a84b436ebb8416486b2a7c63d5565b9148 |
| PTIT.ptit-cpp-timeline | 0.1.2 | fff96345f17fa752e194b8504330e4fe26ccb4a3cc5792db9d5a686aa0072d61 |
| PTIT.ptit-java-timeline | 0.1.2 | 6d18e729be01389ec71772a22c02b32e9da1771c0f8f329b6b5db96e52a058c7 |
| VNPT.vcr-runner | 0.0.1 | 24a1470b6ebe9419e5da4e3991c30b082465c5797fd455e65ad7c43666f0cdab |
| Viettel.vcc-cpp-tools | 0.0.3 | 6b5e1db5ff14b442c12ac42982140fe2f2b97a4d1d105cd8039e1f97f75b4826 |
| Viettel.vjc-java-pack | 0.0.3 | 54b10c24b7c6c1d023bc68f172c07967bd97856a0a3cb717876bf0325106b06d |
| dsanms.dsanms | 0.1.3 | 8511f382990b8b097d77e1942a37faae32e2dac4a613da0bbc580cc0658eb050 |
| Pstudio.search-code-ultra | 0.2.6 | 8d395dcd40e09ed9d10e62070cfd9075f3019b2756c1c1bcc6493bf32bf50334 |
| Ptudios.search-code-fast | 0.1.2 | de2893837a93b0bfba5f4c297d3ce08888c8d034dad47e94a2a9c1ea0e960747 |