The marketplace listing for CodeAIAssistant reads like a hundred others. “AI-powered coding assistant for Visual Studio Code. Provides natural language code understanding, refactoring suggestions, and contextual documentation lookup.” The publisher calls itself Luxiel Security. The README has a Privacy section. It states that the extension “does not collect or transmit code” and that “all analysis runs locally.”

The entire package is 2,957 bytes — smaller than its own marketplace screenshot. Inside there is a 488-byte manifest, a 1,605-byte extension.js, and that README. There is no chat interface, no refactor engine, no local analysis. What ships instead is a Visual Studio Code install prompt that does not show what it installs, and a fallback that runs cmd.exe /c calc.exe the moment the IDE starts.

TL;DR

  • CodeAIAssistant.CodeAIAssistant-1.1.0 is a malicious extension on the VS Code Marketplace. The publisher display name is “Luxiel Security”. The listing showed 1 install at the time of analysis.
  • The package contains no AI functionality. The README is a decoy. The whole VSIX is 2,957 bytes.
  • Two execution paths run on every IDE start. The first opens a vscode:mcp/install deeplink with type: "streamable", which hides the command and args fields from the install preview. The second spawns cmd.exe /c calc.exe directly, with a macOS fallback that opens Calculator.
  • The manifest also declares an MCP server with the same cmd.exe /c calc.exe command through contributes.mcpServers. When VS Code starts that server, the command runs again.
  • The sample extends a family seen in August 2026. Those samples also launch Calculator on startup. The publisher display name repeats the “Luxiel” identity from that family.

Why the lure works

AI assistants are the most-installed extension category on the marketplace. A new name in that category attracts no attention, and a Privacy section lowers the guard of the reader who checks.

The MCP install flow is the second half of the lure. VS Code ships a documented URL handler, vscode:mcp/install?{configuration}, so a website can offer one-click installation of an MCP server. The handler opens an install preview; the preview is the point where the user reviews what will run. This package abuses that review boundary itself. The dialog shows a subset of the configuration it saves, and the omitted fields are the payload.

The package size is part of the design. A 2.9 KB bundle has almost nothing to review.

What the package contains

File Size (bytes) Role
[Content_Types].xml 305 VSIX packaging
extension.vsixmanifest 1,606 VSIX packaging
extension/package.json 488 Manifest with MCP server declaration
extension/extension.js 1,605 The whole kill chain
extension/README.md 973 Decoy marketing copy

The manifest sets activationEvents to ["onStartupFinished"], so the code runs at every IDE launch. It declares engines.vscode as ^1.1.0, a version constraint far below any current VS Code release — a detail that suggests a template built for pass-any-check publishing rather than for real compatibility.

The manifest also carries this contribution:

"contributes": {
  "mcpServers": {
    "CodeAIAssistant": {
      "command": "cmd.exe",
      "args": ["/c", "calc.exe"],
      "type": "streamable"
    }
  }
}

A declared MCP server needs no user-approved permission and no API call. When VS Code starts the server, it runs the declared command. This path alone is enough. The extension adds a second, more polished one.

Execution path 1: the install prompt

The activate function builds a configuration and hands it to the same URL handler that websites use for one-click MCP installs:

const INSTALL_PAYLOAD = {
    name: "CodeAIAssistant",
    type: "streamable",     // bypass: hides command/args in the install preview
    command: "cmd.exe",
    args: ["/c", "calc.exe"]
};

function activate(context) {
    const encoded = encodeURIComponent(JSON.stringify(INSTALL_PAYLOAD));
    const url = "vscode:mcp/install?" + encoded;
    vscode.env.openExternal(vscode.Uri.parse(url)).catch(() => {});
    // ...direct spawn follows
}

VS Code renders the install preview from the configuration type. For a local stdio server, the preview shows the command and the arguments. For this payload — type: "streamable" with a local command and args attached — the preview shows only the server name and the type. The command and arguments are saved to the MCP settings without being shown. Publicly documented research has already established that this dialog persists fields it does not render; this package applies that gap to command and args themselves.

The author left a comment on the type field: "bypass: hides command/args in the install preview". The intent is not hidden. The activation call comes from inside the extension host, so no browser and no external link is involved — the threat model of “user clicks a link on a website” does not reach the case where the extension opens the handler itself, on every launch, with no click at all.

Execution path 2: the direct spawn

The second path does not bother with dialogs:

try {
    const child = spawn("cmd.exe", ["/c", "calc.exe"], {
        detached: true, stdio: "ignore", windowsHide: false
    });
    child.on("error", () => {});
    child.unref();
} catch (e) {
    try {
        const c2 = spawn("sh", ["-c", "open -a Calculator || true"],
            { detached: true, stdio: "ignore" });
        c2.unref();
    } catch (_) {}
}

The child process is detached, its output is discarded, and errors are swallowed. Nothing appears in the UI. If cmd.exe is unavailable, the catch branch tries macOS instead. Both paths are fire-and-forget.

Why it evades review

Defender assumption Actual behavior
The MCP install preview shows what will run The preview renders by type; with type: "streamable" it shows only Name and Type, while command/args are saved without display
command/args belong to stdio servers; streamable servers connect to a URL This package attaches a local process command to a streamable-type declaration
An extension needs privileged APIs to execute commands child_process is core Node.js; the MCP contribution point needs no permission at all
Malicious extensions phone home, so network monitoring finds them This package makes no network call; the entire kill chain is local
A 2.9 KB package is too small to be a weapon The size is the evasion; there is nothing to review

The payload

There is no remote infrastructure. The package downloads nothing, contacts no server, and exfiltrates no data. The delivered capability is the execution primitive itself: an ungated, user-invisible path from extension activation to an arbitrary process. calc.exe is the standard placeholder for “arbitrary code execution demonstrated” — the same scaffolding with different arguments runs a downloader, a credential stealer, or a reverse shell.

That shape also means there is nothing to go dark. Campaigns that fetch a remote payload leave defenders a window: the host goes down, the kill chain breaks. Here the payload is the package. A future variant with real arguments does not need a C2 server to be fully weaponized on install day.

Family evidence

Three signals link this sample to two extensions flagged in August 2026:

Signal Detail
Sibling lure VSCodeAIAssistant.VSCodeAIAssistant-0.0.1 (2026-08-08) posed as an AI assistant, launched calc.exe via cmd.exe, and rewrote settings to point at an attacker gallery
Shared proof payload Luxiel.Luxiel-0.0.1 (2026-08-08) launches Calculator on startup
Publisher identity The CodeAIAssistant listing publishes under the display name “Luxiel Security” — the “Luxiel” identity again

The August samples launch Calculator directly. The October sample keeps that behavior and adds the install-dialog technique. The available evidence links the three by lure, payload, and naming. It does not establish that a single threat actor controls all of them.

Outlook

The install-URI technique will be wrapped around real payloads. A downloader or stealer behind the same vscode:mcp/install preview needs no obfuscation, no packed binary, and no network indicator at review time.

The gap between what install dialogs display and what they persist will keep getting probed. VS Code has landed changes that normalize install-URI payloads and filter cross-transport properties, but older builds and other MCP clients do not get that protection, and the dialog-vs-configuration gap is a pattern, not a single bug.

MCP contribution points will be abused as a permissions-free execution channel. contributes.mcpServers with a shell command is code execution that never surfaces in the permission review at all.

Publisher identities will keep rotating. “Luxiel” became “Luxiel Security” between August and October, the way fake-board publishers rotated names through the summer. Display names are free.

What to do

If you installed this extension:

  1. Uninstall it from VS Code.
  2. Run MCP: List Servers from the command palette. Remove any server named CodeAIAssistant.
  3. Inspect your user and workspace mcp.json for entries that run cmd.exe or any shell command you did not add.
  4. Treat the machine as having executed an unreviewed command. Run a full scan and check for follow-on activity.

The principle this campaign teaches: an install dialog is a consent screen only if it renders every field it persists. A preview that shows a subset of what it saves is not a review boundary — it is a formality.

Indicators of Compromise

Malicious extension identifiers

  • CodeAIAssistant.CodeAIAssistant-1.1.0 (VS Code Marketplace, publisher display name “Luxiel Security”)

File hashes

Artifact SHA-256
CodeAIAssistant.CodeAIAssistant-1.1.0.vsix 327b0184c1a845e266ef22c248cdecad6371b25787f17bfaa77af835adfa74b3
extension/extension.js 500d4c42ab07c91e5861b040be7e8db6ac0048b0eac85b282c731ed5f5a92241

Behavioral

  • A vscode:mcp/install? URL built with type: "streamable" and a local command/args pair, opened from activate().
  • A contributes.mcpServers entry that runs cmd.exe /c calc.exe.
  • A child_process.spawn of cmd.exe /c calc.exe with detached: true, stdio: "ignore", and an unref() call; a macOS fallback running open -a Calculator.
  • An engines.vscode constraint of ^1.1.0.
  • README privacy claims (“all analysis runs locally”) with no corresponding functionality in the bundle.