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:
- It reads a release identifier from the URL path with
get_release_from_path. - It downloads or starts the matching VS Code server build.
- 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.
Why the session cookie matters
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:
- The attacker has network access to the
serve-webendpoint. - A user has an active, previously authenticated VS Code web server session.
- The attacker persuades that user to open a specially crafted link.
- An unauthenticated request selects and starts an older release, using the current installation's account and connection token configuration.
- 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-webendpoint 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 onetknparameter. 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 theSec-Fetch-Siteheader 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.
3. Cookie hardening
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 whenSec-Fetch-Sitereports cross-site or same-site.rejects_duplicate_connection_token_queries: repeatedtknparameters 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-webbound to localhost. - Do not expose
serve-webdirectly to untrusted networks. - Add an additional authentication layer in front of reverse proxy deployments.
- Do not open unexpected
serve-weblinks 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
UpdateModepolicy is set tonone, 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-webrequest router in 1.145.2 and earlier. - Fixed version: 1.145.3.
- Conditions for the documented attack:
- the
serve-webendpoint 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.
- the
- 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
- NVD: CVE-2026-120780
- CVE Record: CVE-2026-120780
- CVE record API (includes CISA SSVC assessment)
- Microsoft Security Update Guide: CVE-2026-120780
- GitHub Security Advisory: Remote Code Execution via serve web Release Downgrade
- GitHub Security Advisory (API)
- Issue #347429: Remote Code Execution via serve web Release Downgrade
- Issue #347429 (API)
- Commit e45c3db: authenticate requests before release routing
- Commit e45c3db (API)
- Visual Studio Code 1.145 release notes
- Manage updates in enterprise environments
- Visual Studio Code FAQ
- Workspace Trust
- microsoft/vscode Security Advisories
- microsoft/vscode docs Security Policy
- Zero Day Initiative: The November 2026 Security Update Review
- VulDB: CVE-2026-120780
- 2025 Stack Overflow Developer Survey: Technology
- CSRB Review of the Summer 2023 Microsoft Exchange Online Intrusion
- Microsoft Secure Future Initiative: April 2025 progress report
- Related VS Code advisories: Fetch Web Page OS protocol handler remote code execution, Fileless RCE in VS Code Web Remote Terminal via URL Controlled NODE_OPTIONS, VS Code web deployments: RCE via NODE_OPTIONS import from URL payload



