| 💡 Kirin runs in the developer's IDE and blocks malicious extensions and packages before they execute. Try it free for up to 5 licenses. |
What Happened
AgentMesh automatically discovered a malicious VS Code extension that fetches and executes operator-controlled shell commands on every VS Code startup, targeting developers on Windows, macOS, and Linux. Extension has been removed from the VS Code Marketplace. No scan engines on VirusTotal flagged the sample at validation time.
Remote Text Fetcher v0.0.1
|
Field |
Value |
|
Marketplace ID |
DorianN612.remote-text-fetcher |
|
Publisher |
DorianN612 (unverified) / GitHub: DorianKalliope |
|
Published |
May 27, 2026 |
|
Installs |
0 (caught before distribution) |
|
AgentMesh |
extensions/128356 — CRITICAL / DANGEROUS |
|
VirusTotal |
0 detections |
|
SHA-256 (VSIX) |
8136e6e1260e85c860c26245e7622c8bc2f82d741afb445e9ddccaee78990f4b |
|
SHA-256 (extension.js) |
4392173461fb74e295021d6ef9f74260181d8c2a27b6e43fa1a697422cf3a9e0 |
|
MD5 (VSIX) |
256347f689733a99899415f818d29818 |
Behavior: Remote Text Fetcher is not a text utility. On every VS Code startup (activationEvents: ["onStartupFinished"]), it reads a URL from the VS Code config key agentService.url, issues an HTTP GET, base64-decodes each line of the response, and executes each decoded string via child_process.exec. No user interaction required. The VSIX contains no embedded payload — the attacker controls what runs by serving commands from the C2 URL.
Simple attack flow
- User installs the Remote Text Fetcher VS Code extension.
- On every VS Code startup (activationEvents: ["onStartupFinished"]), the extension activates automatically.
- The extension reads a hidden configuration value from agentService.url — a namespace not declared in package.json.
- The URL can be pre-seeded by the attacker through a malicious .vscode/settings.json file in a cloned repository or workspace.
- The extension sends an HTTP GET request to the configured URL.
- The server responds with newline-separated base64-encoded shell commands.
- The extension decodes each line and executes it via child_process.exec.
- All fetch and decode errors are silently ignored.
End result: arbitrary shell command execution on the developer workstation every time VS Code starts.
IoCs
|
Type |
Value |
|
Config key read (undeclared) |
agentService.url |
|
Config key declared (decoy) |
remoteTextFetcher.url (does nothing) |
|
C2 fallback (compiled JS) |
http://localhost:3000/file.txt |
|
C2 fallback (initial TS source) |
http://localhost:3000/commands.txt (commit f3c3bea0) |
|
Live C2 |
Operator-supplied via agentService.url — not hardcoded in artifact |
|
C2 protocol |
HTTP GET → newline-separated base64-encoded shell commands |
|
Execution |
child_process.exec(Buffer.from(line, 'base64').toString('utf8')) |
|
Error handling |
Fetch and decode errors silently ignored |
|
Install path (Windows) |
%USERPROFILE%\.vscode\extensions\DorianN612.remote-text-fetcher-0.0.1\ |
|
Install path (mac/Linux) |
~/.vscode/extensions/DorianN612.remote-text-fetcher-0.0.1/ |
|
GitHub |
|
|
Internal dev name |
agent-service (CHANGELOG.md, commit f3c3bea080fd) |
Payload analysis: No live payload captured during analysis. Runtime execution chain characterized through static analysis of the VSIX artifact.
Config namespace mismatch (key finding)
The package.json declares remoteTextFetcher.url — visible in the VS Code Settings UI. The compiled extension.js reads agentService.url — an undeclared namespace, invisible to the user and to any reviewer inspecting package.json alone.
The GitHub TypeScript source was sanitized post-publication in two commits, but the compiled VSIX was never rebuilt. The malicious agentService.url read survives in the shipped binary. The internal development name agent-service (CHANGELOG.md, commit f3c3bea080fd) maps directly to the agentService config namespace, confirming the mismatch is intentional.
Git timeline (DorianKalliope/remote-text-fetcher):
|
Commit |
Action |
|
f3c3bea080fd |
Initial commit — agentService namespace, URL: localhost:3000/commands.txt |
|
b852cfabee0a |
Partial sanitization — URL updated to file.txt, namespace still agentService |
|
f4627a742da6 |
Full sanitization — namespace renamed to remoteTextFetcher in TS; VSIX not rebuilt |
|
bbfd0cf03ecd–9e163cdd7688 |
12x automated vcs-metadata.txt commits |
Publisher seeding
Two days before publishing the malicious extension, DorianN612 published a clean functional extension (“RealTime Word Counter”), likely intended to establish marketplace credibility.
Extension ID: DorianN612.wordcountertool
Published: May 25, 2026
SHA-256: 142cd54412362ca249a3feffb263c67fd1a200176254d66cb173c98376dbcf7b
AgentMesh classified the extension as SAFE:
https://agentmesh.knostic.ai/extensions/122264
Static analysis found no malicious functionality. Unlike Remote Text Fetcher, the source and compiled artifacts matched exactly.
Detection anchors
- Extension JS reads config namespace not declared in its own package.json
- Buffer.from(<var>, 'base64').toString('utf8') passed directly to child_process.exec
- onStartupFinished + outbound HTTP fetch + no declared commands or UI contribution
- agentService.url present in any VS Code settings file (workspace or user scope)
- CHANGELOG.md internal name differs from published extension name
- Source/compiled divergence: TS source and compiled JS use different config namespaces
Subscribe to our blog!
Tags: