Introduction
A malicious Model Context Protocol (MCP) server could place a clickable workbench command inside an ordinary Visual Studio Code notification, and a single click on that link could run code with the user's permissions. Developers are wiring their editors into a growing number of remote MCP servers, and this bug shows how text supplied by an integration can cross into command execution when a renderer is too generous about what it parses.
Microsoft tracks the issue as CVE-2026-120779, classified as CWE-94 (code injection). Microsoft supplied a CVSS 3.1 base score of 9.6 (Critical), while its own maximum severity rating in the Security Update Guide is Important. These are different scales, and both are reported here. At original publication Microsoft listed the bug as not publicly disclosed, not exploited, and "Exploitation Less Likely". The NVD record carries a CISA Coordinator SSVC assessment of exploitation: none, automatable: no, technicalImpact: total. The fix shipped in VS Code 1.145.3 on November 10, 2026.
For a sense of reach, the 2026 Stack Overflow Developer Survey reports 70.9% usage for VS Code and describes it as the most-used IDE. That figure reflects survey respondents, not the number of vulnerable installations or how many users actually connect to remote MCP servers.
Technical information
Where server text meets the notification renderer
MCP servers can send VS Code an elicitation/create request, which asks the user for input. Normally VS Code surfaces this inside a chat session. When no chat session is available, McpElicitationService falls back to a regular workbench notification (plus a quick pick for the form flow).
The problem lies in how VS Code's notification service handles its message field. A plain string is treated as linked text: Markdown-style links in the string are parsed and rendered as clickable links, and that includes command: URIs, which execute workbench commands when clicked. Before the fix, the server-controlled message value from the elicitation request went directly into that renderer. A malicious server could therefore shape its message into a link that invokes a command such as workbench.action.terminal.sendSequence.
The URL elicitation fallback had the same weakness with an extra twist. The old code built its notification by joining raw strings: the server's text plus VS Code's own localized "This will open ..." instruction. The renderer then parsed the combined string for links as a whole, so it could not tell server text from trusted UI text.
This lines up with MITRE's definition of CWE-94: a code segment (here, a command link) is constructed from externally influenced input without neutralizing the elements that change its intended behavior.
A second path: messages that are not strings
MCP messages are JSON, so nothing in the protocol itself forced message to be a string. A server could send an object instead. The regression tests added with the fix use an object containing a _nodes array of { label, href: 'command:...' } entries. That shape imitates the internal structure the notification renderer uses for text it has already parsed into link nodes. Because the renderer would treat such a value as pre-parsed content, it could carry a command link past any fix that only escaped string input.
Attack flow
Based on Microsoft's advisory and the patch materials, the documented scenario is:
- The attacker controls a remote MCP server. No authentication to the victim is required.
- The attacker persuades the user to connect Visual Studio Code to that server.
- The server sends an
elicitation/createrequest at a point where no chat session is available, so VS Code falls back to a workbench notification. - The request's
messageis crafted as a Markdown link pointing at acommand:URI (the regression test uses a message shaped like[Open details](command:workbench.action.terminal.sendSequence?...)), or as an object mimicking the renderer's_nodesstructure. - The notification renders the attacker's link as clickable.
- The user clicks the link, the workbench command executes, and code runs with that user's permissions.
Two user decisions are required: connecting to the server and clicking the notification link. The advisory does not describe passive display of the notification, or an unsolicited network connection, as sufficient.
Severity scoring
The base vector supplied by Microsoft is:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
That is a network attack vector, low complexity, no attacker privileges, required user interaction, changed scope, and high impact to confidentiality, integrity, and availability. Microsoft's full vector adds the temporal metrics E:U/RL:O/RC:C (Unproven exploit maturity, Official Fix, Confirmed report confidence), giving a temporal score of 8.3. NVD has not supplied an independent assessment. Changed scope does not imply elevated execution. The advisory states that code runs with the permissions of the user, and makes no claim of administrator or SYSTEM execution.
Patch information
Microsoft fixed the bug in Visual Studio Code 1.145.3, released November 10, 2026. The MSRC entry lists the remediation level as Official Fix with 1.145.3 as the fixed build. The matching GitHub advisory, GHSA-66hq-jw93-462h, covers versions < 1.145.3 and names two public commits as the fix, 305e2483 and e3a49623, both tagged with MSRC case 141292. In the advisory's words, the fix works by "rendering elicitation messages as literal text and validating the request payload before displaying it."
Fix 1: render the message as literal text (305e2483)
The first commit wraps every server-controlled message in NotificationText.concat(...). This explicit text type tells the notification layer to render the content exactly as written rather than parsing it for links. It covers both fallback paths, the form fallback and the URL elicitation notification:
+import { NotificationText } from '../../../../platform/notification/common/notificationMessage.js'; ... // Fallback: no chat session → notification + quickpick const handle = this._notificationService.notify({ - message: elicitation.message, + message: NotificationText.concat(elicitation.message), ... - message: elicitation.message + ' ' + localize('mcp.elicit.url.instruction2', 'This will open {0}', elicitation.url), + message: NotificationText.concat(elicitation.message, ' ', localize('mcp.elicit.url.instruction2', 'This will open {0}', elicitation.url)),
In the URL path, each piece now goes in as separate literal content instead of being joined into one string that is parsed for links. A new regression test sends a message shaped like [Open details](command:workbench.action.terminal.sendSequence?...) and checks two things: that the notification is a NotificationText instance, and that the rendered linked text nodes contain only the original string, with no link node created.
Fix 2: reject messages that are not strings, in two places (e3a49623)
The second commit closes the object payload gap described above. It adds a type check at two layers.
Where requests arrive, in mcpServerRequestHandler.ts, an elicitation/create request is checked before any further handling, including the task-augmented branch:
} else if (request.method === 'elicitation/create' && this._elicitationRequestHandler) { + if (typeof request.params?.message !== 'string') { + throw new McpError(MCP.INVALID_PARAMS, 'Elicitation message must be a string'); + }
Where the UI service starts, in mcpElicitationService.ts, elicit() repeats the check before choosing the form or URL flow, so a malformed payload never reaches notification code by any route:
public elicit(server: IMcpServer, context: IMcpToolCallContext | undefined, elicitation: MCP.ElicitRequest['params'], token: CancellationToken): Promise { + if (typeof elicitation?.message !== 'string') { + return Promise.reject(new MpcResponseError('Elicitation message must be a string', MCP.INVALID_PARAMS, undefined)); + }
Malformed requests are refused with a standard JSON-RPC INVALID_PARAMS error rather than being silently coerced into a string. Tests cover form, legacy (no mode), URL, and task-augmented requests, confirming that each is rejected, that zero notifications are shown, and that the elicitation handler is never called.
Why both commits matter
The two changes block different attacks. Fix 1 stops a string message from being interpreted as Markdown with command links. Fix 2 stops an object message that imitates the renderer's internal structure, and does so before the payload gets near the UI. Checking at both the request handler and the UI service means a later refactor of either layer is less likely to quietly reopen the hole. Both fixes are present in VS Code 1.145.3 and later.
Applying the update
The 1.145.3 release notes recommend using Check for Updates. Microsoft's download page, linked from the advisory, is the alternative. The VS Code FAQ notes that the product installs updates automatically when they become available, and that the installed version can be confirmed in the About dialog (on macOS, Code > About Visual Studio Code).
Supplementary MCP controls
Microsoft documents several MCP governance controls. None is presented as a fix or workaround for this CVE, and the advisory has no dedicated workaround section, so treat these as additional layers rather than substitutes for patching:
- ChatMCP policy set to
registryOnly: restricts MCP servers to a curated registry. - ChatMCP policy set to
off: disables MCP support entirely. - Trust and permission review: review repository MCP configuration and server provenance, prefer session-scoped permissions, and approve startup, sign-in, and tool approval prompts only when the generated commands, arguments, and credential requirements are understood.
The sandbox Microsoft documents for locally running MCP servers over stdio applies to a different execution context than the remote-server scenario here, and should not be considered a mitigation for this bug.
Affected systems and versions
- Product: Microsoft Visual Studio Code.
- Affected range (CVE record, Microsoft CNA): from 1.0.0 before 1.145.3.
- Affected range (GHSA-66hq-jw93-462h): versions
< 1.145.3. - Fixed version: 1.145.3, and any later release.
- Vulnerable configuration: exploitation requires the user to connect VS Code to an attacker-controlled remote MCP server and to click a crafted link in a notification shown through the elicitation fallback path (no chat session available).
- Platforms: the published product entry does not distinguish operating-system-specific exposure or separate platform patches.
Vendor security history
A separate Microsoft GitHub advisory, GHSA-r2gr-w3c8-wvqv, dated September 8, 2026, documented a Workspace Trust bypass in VS Code 1.136.1 and earlier. An attacker could persuade a user to open a crafted workspace that connected to an attacker-controlled service while in Restricted Mode. The advisory attributes it to incomplete enforcement of Workspace Trust restrictions. Microsoft fixed it in 1.136.2.
That issue is not CVE-2026-120779, and updating to 1.136.2 does not address this bug. Its relevance is narrower. Taken together, the two advisories show that VS Code's integration surfaces (workspaces, external services, MCP servers) have produced trust boundary failures in consecutive releases, and that the presence of a trust feature does not guarantee every integration path is covered. In both cases Microsoft published an advisory and a patched build. The MSRC advisory for CVE-2026-120779 credits William Conlon, Dohyeok Kim, and Myungyong Lee for the report.
References
- NVD entry for CVE-2026-120779
- CVE Record: CVE-2026-120779
- Microsoft Security Update Guide: CVE-2026-120779
- GitHub Security Advisory GHSA-66hq-jw93-462h (API)
- Fix commit 305e2483 (API)
- Fix commit e3a49623 (API)
- Fix commit 305e2483 on GitHub
- Fix commit e3a49623 on GitHub
- NVD API record for CVE-2026-120779
- Visual Studio Code 1.145 release notes
- Secure AI assisted development in VS Code
- Add MCP servers in VS Code
- Visual Studio Code FAQ
- CWE-94: Improper Control of Generation of Code
- GHSA-r2gr-w3c8-wvqv: Workspace Trust bypass through attacker controlled services
- microsoft/vscode security advisories
- GitHub Security Advisory GHSA-6xq8-9qf3-p6qv (API)
- CISA Known Exploited Vulnerabilities Catalog
- CISA KEV JSON feed
- Zero Day Initiative: The November 2026 Security Update Review
- BleepingComputer: Microsoft November 2026 Patch Tuesday
- Stack Overflow Developer Survey 2026: Technology data
- MSRC FAQs: Report an issue
- StackFlag: CVE-2026-120779
- Security and Trust in Visual Studio Marketplace
- Celebrating 50 Million Developers: The Journey of Visual Studio and Visual Studio Code



