A VS Code MCP Install Link Could Hide the Code That Ran

VS Code's MCP install dialog hid env, headers, and a path to code execution. Update past 1.145.3, then read every mcp.json.

By Muhammad Saif and Aashan Khan · Techtribe co-founders

The coding assistant in VS Code is only as safe as the tools it is allowed to start. In 2026 that assumption failed in the install dialog itself. Oasis Security found that a single click on a crafted link could write a configuration the preview never showed, and that the hidden fields were enough to run code on the developer's machine or to send the assistant's tool calls through someone else's account. Microsoft assigned CVE-2026-41613. The fix that renders env, envFile, and headers in the preview shipped in VS Code 1.119.1.

That bug is not the whole attack surface. Through the autumn Microsoft published further MCP advisories: sandbox approvals shared across servers, gallery metadata that could write outside the server's folder, and, on November 10, command links inside an MCP elicitation notification, fixed in 1.145.3. Each one is a different door. The pattern is the same. The editor grew a way for an outside party to hand the assistant a tool, and the moment a person was supposed to look was narrower than the thing being installed.

The general problem, a tool description that poisons the model after you connected a server you meant to trust, is written up in whether the MCP servers your agent uses are safe. This note is the editor bug: the click, the dialog, and the files already on disk.

The dialog was the only review

VS Code lets a web page, a document, or a chat message offer an install link for an MCP server. The person clicks, a preview opens, they press Install, and the configuration is written into the workspace. Oasis's point is that this dialog is the security boundary. It is the only moment a human sees a configuration that arrived from outside the repo. Everything after that is the server starting, on reload or by hand, with whatever was saved.

The preview showed five fields. Five more were stored and not drawn. Among the silent ones were environment variables and HTTP headers. The payload did not need a separate exploit window. It needed to be present in the link and absent from the picture.

The attack they describe is ordinary to look at. Someone shopping for a server lands on a polished list, finds the GitHub server they expected, and clicks "Add to VS Code." The preview shows a familiar package name, command, and arguments. Install does what the link said, including the fields the preview skipped. The next start of that server loads the hidden settings. Those settings can tell the program to run the attacker's code before the server's own logic. No password prompt is required at that step. The person already pressed Install on a dialog that looked finished.

A second use of the same hole does not need a shell. Another hidden field is the network identity attached to the tool's requests. An attacker can plant their own credentials in the link. When the tool connects, it connects as the attacker. The assistant keeps working. The files it reads, the messages it sends, and the edits it makes happen inside the attacker's account, and they show up in that account's logs and in any system the account can reach. Oasis's line for it is the right one: not a phishing page, and not a stolen password. A link that looked like an install.

Microsoft's fix in 1.119.1 puts env, envFile, and headers on the preview, which is the correct patch for that lie. A preview that shows the fields can still be clicked through by someone who does not know what an environment variable is. The patch restores the chance to refuse. It does not restore judgment. After you update, the habit that matters is reading the fields the dialog now shows, not celebrating that they exist.

What to look for in a link, even on a patched editor

An install link is a serialization of a config. The fields that change what runs are the command, the arguments, the working directory, the environment, and the headers. A command of npx with a package you recognize is not innocent if env points NODE_OPTIONS at a file, or if cwd is a directory the attacker expects you to have. A header that looks like an API token is the identity bug: the server will present that token, and the assistant will not announce that it is no longer you.

Treat a missing field as a field. If the dialog on your version does not mention environment or headers at all, you are on a build from before the fix, and you should not press Install. Update first. If the dialog shows them and they are empty, that is a different statement from a dialog that hides them. Empty means the link did not set them. Hidden means you do not know.

Workspace config and user config are different blast radii. A server written into the repo's .vscode or project MCP file travels with the clone. A server written into the user profile hits every folder that developer opens. The Oasis bug wrote the workspace configuration. Either store is enough if the server starts with the user's credentials available to the process. The question to ask before Install is which file will receive the JSON, and who else will run it.

Auto-start makes the click durable. A server that launches on folder open does not wait for a second decision. The person who installed it on Monday is not at the keyboard on Thursday when the poisoned env runs. If you do not need the server for every session, do not leave it on "start with the workspace." A tool you invoke on purpose is a smaller window than a tool the editor invokes because the folder opened.

The bugs that shipped after the install dialog

Updating to 1.119.1 closes the silent-field hole Oasis reported. It does not close the MCP holes Microsoft documented later. The version to be on, if you want one number for this set, is 1.145.3 or newer.

On November 10, 2026, Microsoft published GHSA-66hq-jw93-462h. VS Code 1.145.2 and earlier had a fallback path for MCP elicitation notifications. A server can ask the user for something it needs, and if that request cannot be shown the normal way, the editor fell back to a notification. The message in that notification could be read as an interactive command link. A malicious server could put a command in the text. If the user activated the link, the command ran. The attacker needs a connected server and a click. That is a lower bar than it sounds once the team has been told that installing servers is how the assistant gets useful. The patch renders elicitation messages as literal text and validates the payload before display. The workaround until you update is the one the advisory gives: only connect trusted servers, and do not activate links in notifications that came from a server you do not trust.

On October 13, 2026, GHSA-qghm-w43w-vx8v described a sandbox bypass by sharing. In 1.141.0 and earlier, permission approvals for the MCP sandbox were saved in a shared sandbox configuration, not on the server that asked. Network access and filesystem writes you approved for one server could apply to another server using that same configuration. An attacker-controlled server, placed in a configuration that already contained someone else's approval, could use the approval without a second prompt. The fix in 1.141.1 scopes grants to the individual server, restricts shared configuration to deny rules, ignores legacy shared grants, and writes server-specific sandbox files. Until that build, the workaround is to avoid approving extra network or write access in any configuration that also contains a server you did not review.

On September 8, 2026, GHSA-g6p5-6xp8-5jwg covered gallery metadata. VS Code built a metadata directory from the server's name and version without checking that the path stayed inside the MCP storage directory. Gallery or registry metadata could redirect writes, overwrite another server's manifest.json or README.md, write outside that directory, or, on uninstall, delete a directory that was not the server's. The user still has to install or update. The patch in 1.136.2 checks that the resolved path is a single directory component inside MCP storage, and checks uninstall targets against the path derived from that server's name and version. The workaround is to stop installing from galleries you cannot name.

Earlier, in February 2026, GHSA-6xq8-9qf3-p6qv fixed a case where workspace trust was not always required before an MCP server started, in versions before 1.109.1. The practical line was: do not use Copilot on an untrusted workspace on those builds. It is the oldest of this set, and it is the same idea. A folder you cloned is allowed to start a process because an assistant feature wanted a tool.

Four advisories in one editor is not a reason to abandon MCP. It is a reason to stop treating the editor version as a detail. The install dialog, the notification, the sandbox file, and the gallery path are four places a "tooling" feature became code execution or a confused permission. They were patched on different days. A team that updated in September for the path traversal was still exposed to the November notification bug. "We patched VS Code" is incomplete until someone says the version.

The config that is already on disk

The patches change what a future click can hide. They do not rewrite the mcp.json files a past click already wrote. Oasis's advice after the fix is to audit the configurations you have. That audit is a file read, not a feeling about which links the team usually clicks.

Open every mcp.json the editor will load: the workspace, the user profile, and any folder a multi-root workspace adds. For each server, read the command, the arguments, env, envFile, headers, and cwd. A key you do not recognize in env is the install bug's residue. A header that contains a bearer token is the identity bug's residue. An envFile that points outside the repo is somebody else's file being loaded into the tool's process. A cwd you did not choose is the directory the payload expected.

Then ask whether that server starts on its own. A config nobody can explain should be removed, not disabled "for later." Disabled servers have a habit of being re-enabled by the next person who wants the tool. Removal is a diff. A comment is not.

If the hidden environment may already have executed, rotation comes before cleanup theater. The tokens available to that user — cloud keys, GitHub tokens, package-registry tokens — are the blast radius. Removing the JSON entry does not un-read a credential file the payload already opened. Assume the process could do what the user could do, unless you had a sandbox that this server was actually inside. The October bug is a reminder that the sandbox you approved for a different server may have been the one this server inherited.

Pin the editor version in the same place you pin CI images, if developers install from a managed channel that can lag. A laptop on the stable channel from August is not protected by a patch note from November. The check is the version string on the machine, not the version in the blog post the security channel forwarded.

How this sits next to a poisoned tool

CVE-2026-41613 runs code, or swaps identity, before the model has to be tricked. Tool poisoning, the case the MCP server note covers, runs after a server you accepted starts returning text the model treats as instructions. You can have both. A clean install of a malicious server is the supply-chain version. A hidden env on an otherwise real package is the install-dialog version. A server that was honest on Monday and posts a command link in an elicitation toast on Thursday is the November advisory.

Defenses stack in that order. First the editor has to show the config and refuse to interpret server text as a command link. Then the server you kept has to be one you can name, pinned, with a token that cannot do the next-worse thing. Then a person still has to approve calls that leave the machine. Skipping to "we told the model not to follow instructions in tool output" does not address a process that already executed because NODE_OPTIONS was set. The model is not in that path. The operating system is.

Shared sandbox approvals are the version of this that feels like a feature. You approved network access for the documentation server, and the server a teammate added next to it inherited the yes. Least privilege inside one editor profile means the approval is per server. If your build is older than 1.141.1, that is not what the product did. Do not approve a wide grant "for the MCP sandbox" as if it were a single switch you understand. On those builds it was a switch you were sharing.

Gallery installs add a registry you do not operate. The path-traversal bug needed attacker-controlled metadata, which means the registry or the gallery entry was the attacker's. A private list of servers your company builds is a smaller problem than a public gallery with a familiar name. The supply-chain note is the package version of the same decision: a name with downloads is not a review. Pin the version, and prefer a server you can build from a commit you have read.

What to check on each machine

Do this once for every developer who uses Copilot or another VS Code agent with MCP, and again when someone adds a server.

  1. Read the version. It needs to be 1.145.3 or later to include the elicitation fix on top of the earlier MCP patches. If a managed update cannot get there this week, stop installing servers and do not click notification links from a server until it can.
  2. Open every mcp.json that editor loads. Write down the command, arguments, env, envFile, headers, and cwd for each entry.
  3. Delete entries nobody can explain. Do not leave them commented out in a shared repo.
  4. If env or headers contain values you did not set, treat the tokens on that machine as burned. Rotate, then remove the entry.
  5. Confirm sandbox approvals on builds before 1.141.1 were not shared. After you update, old shared grants should be ignored, but a server you do not trust should not be in the file at all.
  6. Turn off auto-start for any server that does not need to run every time the folder opens.
  7. Refuse install links in chat until the person who clicks can see the full config on a patched editor. A screenshot of a gallery page is not the config.

If you cannot list the servers, the version, and whether a hidden env may have run, you do not know what the assistant is allowed to start. The dialog cannot answer that after the fact. The files can.

If this is your app, send the repo.

A 30-minute scope call. We read what is live, name what is dangerous, and quote a fixed scope.

How Techtribe reviews an editor's MCP install

We read the repo and the MCP configs the editor actually loads, including personal ones you are willing to share, and we list the command, the environment, and the headers on each server. You get that inventory in writing, with the editor version next to it. We do not call a gallery link reviewed because the package name looked familiar.

A one-time pass fits when a few developers tried servers and the risk is the laptops plus the tokens on them. A Dedicated Team fits when the whole team installs servers from links and new configs keep landing in the repo. The scope call is 30 minutes with a founder, and it is where we say which of those you are in.

Bring the repo and every mcp.json you can find. If a hidden env may already have run, say that first so we treat the token as burned.

The fixed scope for taking a generated app to production is a page per tool: Lovable, Bolt, v0, and Replit.

Questions

Which VS Code version fixes the MCP bugs in this post?

The install-dialog bug Oasis reported as CVE-2026-41613 was fixed in 1.119.1, which shows env, envFile, and headers in the preview. Later advisories need a newer build. The elicitation-notification bug is fixed in 1.145.3. Update to 1.145.3 or later so one install covers the set.

Does the install preview show everything that gets written?

It does on a patched editor. Before 1.119.1 the dialog rendered five fields and silently stored others, including environment variables and HTTP headers. A link could look like a normal GitHub server and still carry a payload the preview never drew.

Is a trusted-looking MCP link safe to click?

Only if you can see every field that will be saved, and you recognize the command, the arguments, the environment, and the headers. A page titled Awesome MCP Servers is not a review. The review is the config that lands in the workspace.

What if we already clicked an install link?

Open every mcp.json, including ones in home directories, and look for env, envFile, headers, and cwd you did not set. If a hidden environment variable may have run, treat the tokens on that machine as burned and rotate them before you argue about the package name.

Book a free call

Have a vibe-coded app in production?

30-minute free call. We'll read what you have, name what is dangerous, and quote a fixed scope.