Automated Threat Modeling

Brief Summary: CVE-2026-120780, a Visual Studio Code Web Server Release Downgrade Enabling Remote Code Execution

A brief summary of CVE-2026-120780, an improper access control flaw in the Visual Studio Code serve web router that let an unauthenticated request start an older server build. The post covers the root cause, the fix in VS Code 1.145.3, and affected versions.

CVE Analysis

10 min read

Gaurav Sarraf
Gaurav Sarraf

2026-11-11

Brief Summary: CVE-2026-120780, a Visual Studio Code Web Server Release Downgrade Enabling Remote Code Execution
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

A single crafted link was enough to make a Visual Studio Code web server start an older, still installed server build, along with whatever weaker security behavior that build carried. Microsoft fixed the issue, tracked as CVE-2026-120780, in VS Code 1.145.3 on November 10, 2026. It scores CVSS 3.1 8.3 (High), carries an Important severity rating, and can lead to code execution with the permissions of the account running the server.

Microsoft classifies the bug as improper access control (CWE 284). The flaw is in the serve-web request router, which is used when VS Code runs as a browser-accessible server. The CVE data lists the vendor as Unknown. The CVE record and MSRC advisory confirm that the product is Microsoft Visual Studio Code, not the separate Visual Studio IDE. This post briefly summarizes the root cause, the fix, and the conditions that limit exploitation.

Technical Information

Root cause: routing ran before authentication

The code serve-web command is implemented in the Rust CLI file cli/src/commands/serve_web.rs. It acts as a front-end router:

  1. It reads a release identifier from the URL path with get_release_from_path.
  2. It downloads or starts the matching VS Code server build.
  3. It forwards the request to that build.

Before 1.145.3, routing happened first. Authentication was left to whichever server build received the proxied request. An unauthenticated request could therefore choose an older installed build and start it under the current installation's account and connection token configuration. According to the GitHub advisory, obsolete security behavior returns to an otherwise updated deployment as a result. The tracking issue says authentication occurred too late, after a release could already be selected or started.

The router accepts the connection token as a tkn query parameter or as a vscode-tkn cookie. The browser attaches the cookie automatically. So a victim who has authenticated to the web server before and then follows a link from an attacker-controlled page brings their session into the release router.

This explains two parts of the CVSS vector. The attacker needs no privileges (PR:N), but the attack still depends on a victim with a previously authenticated session (UI:R).

Attack flow

Microsoft's advisory and FAQ describe this sequence:

  1. The attacker has network access to the serve-web endpoint.
  2. A user has an active, previously authenticated VS Code web server session.
  3. The attacker persuades that user to open a specially crafted link.
  4. An unauthenticated request selects and starts an older release, using the current installation's account and connection token configuration.
  5. If a vulnerable older server build is available, that version runs, and code execution with the server account's permissions becomes possible.

Microsoft also says that particular protocol settings or configurations must be present, but it does not publish a complete list. The advisory does not limit the issue to any operating system.

Severity in context

The published base vector is:

CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H

What each metric means here:

  • Attack Vector: Network. The attacker reaches the serve-web endpoint over a network path.
  • Attack Complexity: High. Success depends on conditions the attacker does not control, such as a vulnerable older build being available.
  • Privileges Required: None. The attacker does not need to authenticate first.
  • User Interaction: Required. The victim must open the crafted link.
  • Scope: Changed. Impact can reach beyond the router's own security scope.
  • Confidentiality, Integrity, Availability: High. These reflect code execution as the server account.

Microsoft's full vector adds E:U/RL:O/RC:C: Unproven exploit maturity, an Official Fix, and Confirmed report confidence. That gives a temporal score of 7.2, compared with the 8.3 base score.

Exploitation status

At publication, Microsoft recorded "Publicly disclosed: No", "Exploited: No", and "Exploitation Less Likely". The CISA SSVC assessment in the CVE record, dated November 10, 2026, reports "exploitation: none", "automatable: no", and "technical impact: total".

The public issue and commit show the mechanism and the fix, but the sources we reviewed contain no working public exploit. No threat actor, campaign, or indicator set is tied to this CVE. Microsoft credits Sechack and Anonymous. These are research acknowledgments, not threat actors.

Patch Information

Microsoft fixed this in Visual Studio Code 1.145.3, released November 10, 2026. MSRC lists it as an Official Fix with build number 1.145.3. NVD lists versions 1.0.0 up to, but not including, 1.145.3 as affected.

GitHub advisory GHSA xfg5 fq3p cx69 and tracking issue #347429 (milestone 1.145.3, Patch Tuesday) both point to a single public commit, e45c3db29aa2936b2fb81167da3e0ecceaed6053, titled serve-web: authenticate requests before release routing. Connor Peet wrote it, and it references MSRC case ID 143927. The change touches only cli/src/commands/serve_web.rs, adding 129 lines and removing 3.

1. Authentication runs before routing

In handle(), the router now computes is_authenticated first. Unauthenticated requests get a 403 before the secret mint endpoint or release resolution runs. Before the patch, the branch began with let mut res = if path.starts_with(&ctx.cm.base_path). After the patch it reads:

let is_authenticated = request_has_valid_connection_token(&req, ctx.cm.args.connection_token.as_deref()); let mut res = if !is_authenticated { response::forbidden() } else if path.starts_with(&ctx.cm.base_path)

The new response::forbidden() returns status 403 with the body Forbidden: missing or invalid connection token. With this ordering, a server build can no longer be chosen or launched until the caller proves it holds the token.

2. A strict token validator

The new request_has_valid_connection_token function accepts a token from two places and treats each differently:

let query = req.uri().query().unwrap_or_default(); let mut query_tokens = url::form_urlencoded::parse(query.as_bytes()) .filter(|(name, _)| name == CONNECTION_TOKEN_QUERY_NAME); if let Some((_, query_token)) = query_tokens.next() { if query_tokens.next().is_none() && query_token == expected_connection_token { return true; } } if req .headers() .get("sec-fetch-site") .and_then(|value| value.to_str().ok()) .is_some_and(|site| site == "cross-site" || site == "same-site") { return false; } extract_cookie(req, CONNECTION_TOKEN_COOKIE_NAME) .is_some_and(|connection_token| connection_token == expected_connection_token)
  • Query token (tkn): Accepted from any origin, since putting the secret in the URL already proves the caller knows it. The query must contain exactly one tkn parameter. Duplicate parameters are rejected, which blocks tricks that rely on parsers handling repeated parameters differently. A unit test covers this case.
  • Cookie token (vscode-tkn): The browser attaches this automatically, which is what made the crafted link attack possible. The patch now refuses cookie authentication when the Sec-Fetch-Site header reports a cross-site origin, or a same-site origin such as a sibling subdomain. This is a CSRF-style defense. A logged-in victim who follows a link from an attacker's page no longer carries their session into the release router.

After a request authenticates, the router reissues the token cookie with SameSite=Strict. Browsers then stop sending the cookie on cross-site navigations at all, which still protects it when a browser does not send Sec-Fetch headers:

format!( "{CONNECTION_TOKEN_COOKIE_NAME}={connection_token}; SameSite=Strict; Max-Age=2592000; Path=/" )

The cookie is refreshed only inside if is_authenticated { ... }, so a failed request never receives a valid token. The patch also makes extract_cookie more tolerant of formatting by replacing str.split("; ") with str.split(';').map(str::trim). The token cookie is now found even when a Cookie header uses unusual spacing.

4. An opt-out remains

If no connection token is configured, request_has_valid_connection_token returns true immediately:

let Some(expected_connection_token) = expected_connection_token else { return true; };

The fix therefore enforces authentication only when a connection token is set. Deployments that turn token authentication off get no extra protection from this commit.

Tests

The commit adds three unit tests:

  • authenticates_connection_tokens_before_routing: a query token works even cross-site, a same-origin cookie works, wrong or missing tokens fail, and everything passes when no token is configured.
  • rejects_cross_site_cookie_authentication: a correct cookie is refused when Sec-Fetch-Site reports cross-site or same-site.
  • rejects_duplicate_connection_token_queries: repeated tkn parameters are rejected.

Exposure restrictions from the advisory

The GitHub advisory and the tracking issue list these measures alongside the patch. They are not a substitute for it:

  • Keep serve-web bound to localhost.
  • Do not expose serve-web directly to untrusted networks.
  • Add an additional authentication layer in front of reverse proxy deployments.
  • Do not open unexpected serve-web links from untrusted pages.

Rollout notes for managed environments

  • To check the installed version, use Code > About Visual Studio Code on macOS or Help > About on Windows and Linux. The first Version value is the VS Code version.
  • When the UpdateMode policy is set to none, users cannot update VS Code from inside the application, so 1.145.3 has to go out through your software deployment tooling. Where manual checks are allowed, users can select Help > Check for Updates.
  • The 1.145.3 release notes say the build addresses security issues but do not list this CVE by name. The CVE mapping comes from the security advisory.
  • Workspace Trust and Restricted Mode protect against automatic execution of unfamiliar workspace code. They are not documented as a remedy for this release downgrade.

Affected Systems and Versions

  • Product: Microsoft Visual Studio Code on Windows, macOS and Linux. The separate Visual Studio IDE is not covered by this CVE.
  • Affected range: 1.0.0 up to, but not including, 1.145.3.
  • Affected component: the serve-web request router in 1.145.2 and earlier.
  • Fixed version: 1.145.3.
  • Conditions for the documented attack:
    • the serve-web endpoint is reachable by the attacker over the network;
    • a victim has an active, previously authenticated web server session and opens a crafted link;
    • a vulnerable older server build is available to start;
    • certain protocol settings or configurations are present, which Microsoft has not fully listed.
  • Token-disabled deployments: when no connection token is configured, the new check returns true, so the patch's authentication ordering adds no protection there.

The version range defines which software is affected. Whether a given installation is exposed through this specific workflow depends on how serve-web is deployed.

Vendor Security History

Microsoft's public response to this CVE is easy to trace: an MSRC advisory, a GitHub security advisory, an issue opened and closed as completed on November 10, 2026, and a commit with regression tests for duplicate token queries, missing or unexpected tokens, and cookie restrictions. These artifacts do not show how long Microsoft knew about the problem before disclosure.

On the broader record, the Cyber Safety Review Board's March 20, 2024 report on the 2023 Microsoft Exchange Online intrusion concluded that the intrusion was preventable and that Microsoft's security culture was inadequate and needed an overhaul. Microsoft's April 21, 2025 Secure Future Initiative progress report describes later reforms, including tying a security priority to every employee's performance review and applying Zero Trust principles. Those findings concern Exchange Online and Microsoft generally, not VS Code or this CVE. The reform claims are self-reported.

For context on reach, the 2025 Stack Overflow Developer Survey describes VS Code as the most used IDE for five consecutive years. That makes this advisory relevant to many software inventories, but it is not a count of exposed serve-web endpoints.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization