The Incident
CVE-2026-48989 was published to NVD on June 17, 2026 against Windows-MCP, an open-source MCP server that gives AI agents interactive control of a Windows desktop. The vulnerability sits in the server’s optional sse and streamable-http transports: in versions before 0.7.5, both built the underlying FastMCP server with no authentication provider, and the HTTP middleware returned wildcard CORS headers on every request. The project’s PowerShell tool is enabled by default and dispatches caller-supplied commands to powershell -EncodedCommand running as the Windows user who started the server. The GitHub Security Advisory (GHSA-vrxg-gm77-7q5g) scores the issue at CVSS 4.0 base 8.9 and classifies it as CWE-306, Missing Authentication for Critical Function. The default stdio transport is unaffected, so operators who ship Windows-MCP as a Claude Desktop extension were not exposed on this path; the risk is confined to deployments that enabled HTTP on purpose. The maintainer (CursorTouch) shipped 0.7.5 with the wildcard CORS removed, an opt-in --cors-origins allowlist, and TrustedHostMiddleware to blunt DNS rebinding against loopback binds; the issue was credited to the external reporter @dodge1218.
MITRE ATT&CK coverage:
The Authority Path That Failed
The identity exercising execution authority here is the Windows-MCP server process. It runs as the interactive Windows user, and its tool surface attaches PowerShell by default. The scope it held was the entire ambient authority of that user — every file the user can read, every process they can spawn, every network endpoint their session can reach. The scope it exercised in HTTP mode, before 0.7.5, was handed to whoever could open a TCP connection to the bind address. No principal was ever established at the MCP control plane: FastMCP was built with no auth provider, and the CORS middleware answered every origin, including OPTIONS preflights, which lets a cross-origin browser page cross what the operator was treating as a localhost boundary.
The trust anchor that failed first was the implicit assumption that localhost is an authentication boundary. Wildcard CORS plus missing Host-header validation defeated that assumption from the browser side; any local process on the same host could cross it anyway. The second, deeper failure is that the operator was never asked to authorize code execution: PowerShell ships enabled and must be opted out with --exclude-tools. The gap between held and exercised authority — the user’s full session on one side, an anonymous HTTP caller on the other — was never named in configuration, never surfaced at install, and never required a deliberate signoff.
SecurityV0 Perspective
For any Windows-MCP deployment running an HTTP transport on a pre-0.7.5 version, SecurityV0 would raise unproven_execution against the agent runtime. The finding attaches because a code-execution tool (PowerShell) is present in the resolved tool manifest without a corresponding operator-authored authorization record, and because the transport serving that manifest accepted requests from an identity it never verified. The pattern matches the Langflow Python REPL reference: a dangerous capability wired into the framework default, below the visibility of the deploying operator. The 0.7.5 fix narrows reachability — browser cross-origin and DNS rebinding — but does not establish an authorized principal for loopback HTTP; co-resident processes and browser extensions still inherit the server user’s authority through the same control plane.
The evidence pack would carry the Windows-MCP version string, the active transport (stdio vs. sse vs. streamable-http), the resolved tool manifest with PowerShell present, the bind host and port, the auth middleware state, the CORS allowlist (or *), the TrustedHost configuration, and the OS user the server is running as. Pre-exfiltration, that pack answers: does any agent on this host attach a code-execution tool over a transport whose authentication state does not justify it? Post-exfiltration, it answers: which identity opened the MCP session, from which origin, and which tools/call PowerShell invocations ran under the local user’s authority between the first unauthenticated request and the forensic cutover.
What To Do
- Upgrade Windows-MCP to a release at or beyond 0.7.5 and audit the transport you launch. The HTTP paths before 0.7.5 are unauthenticated by design. Confirm the installed version with
pip show windows-mcp; prefer the current release rather than pinning to 0.7.5 specifically. If you cannot upgrade, run only thestdiotransport, which is unaffected. - Drop the PowerShell tool unless the deployment has an authored reason to carry it. Launch the server with
--exclude-tools PowerShell(and any other code-execution tool the deployment does not require). Treat the opt-in to code execution as a signed configuration artifact, not a developer default. - If HTTP is required, require authentication and lock the origin set. Use the
--auth-key, OAuth, or IP-allowlist options the project documents; set--cors-originsto an explicit allowlist rather than*; and keep the server bound tolocalhostunless a remote caller is specifically authorized. Verify thatTrustedHostMiddlewareis engaged against DNS rebinding. - Inventory every MCP server reachable from the agent host for code-execution tools. Enumerate
tools/listfor each server, match the tool names against a code-execution block list (PowerShell,shell,exec,python_repl, filesystem write), and record which transport (stdiovs. HTTP) exposes them. Any HTTP-exposed code-execution tool without a documented auth story is treated asunproven_execution. - Record every MCP session an agent host accepts, with origin and tool-call history. Collect the
mcp-session-idheader, the requestOrigin, the authenticated principal (or its absence), and the tool-call sequence per session. Keep enough retention to answer which caller invokedPowerShellbetween first contact and your current forensic cutover — HTTP logs that drop the body give you no post-exfiltration leverage.