Microsoft’s Debugger for AI Agents Shipped a Drive-By RCE — and the Fix Never Got a Version Number

On September 25, Imperva Threat Research published its analysis of a vulnerability in DebugMCP, the Microsoft-published VS Code extension that hands an AI coding agent real control of the debugger — breakpoints, stepping, variable inspection, expression evaluation. In version 1.1.4, a developer who merely visited a malicious web page could end up running attacker code on their own machine, in the background, with no further interaction. Imperva describes it plainly as a drive-by.

The detail worth sitting with is not the exploit chain, impressive as it is. It is the remediation. Imperva says the maintainers patched the flaw silently — no version bump, no advisory — and published its writeup only after a 90-day disclosure window. We checked the repository against that claim, and it holds up in an uncomfortable way.

One click of “Install,” one unauthenticated server

DebugMCP lives at github.com/microsoft/DebugMCP — 526 stars at the time of writing — and ships to the VS Code Marketplace as ozzafar.debugmcpextension. Its purpose is to let GitHub Copilot, Cline, Cursor, Codex, Windsurf and other MCP clients drive the debugger instead of having a human paste stack traces into a chat box. Installing it starts a local MCP server on port 3001, with no authentication. That is the whole premise: a privileged local tool endpoint that any agent on the box can call.

Imperva notes the amplifier — the same extension is installable in one click not just on laptops but on shared environments like GitHub Codespaces and OpenVSCode Server, where “local” is a much more generous word than it sounds.

Four weaknesses that only matter together

The chain is a good lesson in how agent tooling fails: every link is individually defensible, and the composition is fatal.

  • No Host or Origin validation. The MCP TypeScript SDK added DNS-rebinding defenses in version 1.24.0 after CVE-2025-66414 — the advisory covering the SDK’s failure to enable that protection by default, rated 8.1 (CVSS v3.1) and 7.6 (CVSS v4.0) when published in December 2025. But the protection only applies automatically when a server uses the SDK’s preconfigured Express app. DebugMCP built its own, and the header-validation middleware was never wired in.
  • A stateless transport that skips the handshake. MCP over HTTP is meant to require an initialize request and an initialized notification before any tool call. The SDK’s StreamableHTTPServerTransport enforces that with a validateSession check — but when sessionIdGenerator is undefined, the check returns immediately and the lifecycle is bypassed entirely. DebugMCP v1.1.4 configured the transport in exactly that stateless mode, collapsing the attack to a single no-cors HTTP request.
  • A file-execution primitive in the tool schema. The start_debugging tool takes a fileFullPath argument and tells VS Code to launch a debug session against it. That is not a bug; that is the product. It only becomes a weapon once an unauthenticated stranger can call it.
  • UNC paths solve the attacker’s reconnaissance problem. Needing the full path of an executable on the victim’s disk sounds like a serious constraint — until you remember Windows accepts \\SERVER\SHARE\path. Imperva pointed the path at an attacker-controlled SMB share; VS Code’s debug infrastructure handed it to the Python launcher, which fetched the remote file and ran it as the victim. Their proof of concept called os.system("calc.exe"), and Calculator opened.

Delivery across the same-origin boundary used classic DNS rebinding: a domain with a 1–2 second TTL, a JavaScript loop polling until the browser re-resolves the name to 127.0.0.1, and then a fetch the browser considers same-origin that lands on the victim’s loopback debugger. Imperva demonstrated it on Firefox 150.0.3 and notes that Firefox added Local Network Access protections in version 153 — a mitigation that exists in Chrome and Firefox but is not yet universal, and is not a substitute for the server checking its own headers.

What the repository actually shows

We pulled the fix commit Imperva cites, 86776b2, directly from the GitHub API. The findings line up with the report and add some texture:

  • The commit is dated 2026-05-24 and its message is, in its entirety, “resolve icms” — a reference to Microsoft’s internal incident-management system. The accompanying test file it adds is titled for two ICM ticket numbers. Nothing in the commit message says “security,” “RCE,” or “rebinding.”
  • It adds a LOOPBACK_HOSTNAMES allow-list and exported isLoopbackHost / isLoopbackOrigin helpers, plus a new debugmcp.bindHost setting defaulting to 127.0.0.1, with a README “Security model” section and a settings warning that changing it to 0.0.0.0 exposes “arbitrary code execution via evaluate_expression and start_debugging” to the network. The new test suite explicitly asserts that attacker.example:3001, rebind.local:3001, and 169.254.169.254 are rejected — the maintainers knew exactly which attack they were closing.
  • The version field in package.json reads 1.1.4 before the fix commit and 1.1.4 after it. The repository carries no git tags and no GitHub releases. Imperva’s statement that the fix shipped without a version bump is verifiably correct at the commit level; the extension has since moved on to 2.4.1.

So a user on 1.1.4 who checked their version number, checked the releases page, and checked for an advisory would have found no signal at all that they were running a remotely exploitable debugger. The fix was real and reasonably thorough. The communication of the fix was an internal ticket number.

The pattern this belongs to

This is the same failure shape we keep documenting. GitLab’s MCP server fell to DNS rebinding against a loopback endpoint holding a personal access token. Backslash found hundreds of MCP servers bound to 0.0.0.0 with command-execution tools attached. CVE-2026-46701 was unauthenticated cross-origin MCP tool invocation. Imperva’s own prior work on the Framelink Figma MCP server (CVE-2025-53967, CVSS 8.0) involved the same custom-Express pattern. The ecosystem has now produced enough of these that “unauthenticated loopback MCP server” should be read as a finding on sight, not a design choice.

The developer-targeting angle is what raises the severity above the CVSS a scanner would assign. Imperva is right to stress it: the compromised host is not a kiosk, it is a machine holding cloud CLI sessions, SSH keys, tokens in VS Code secret storage, an open VPN tunnel, and push access to production branches. A payload running as that user inherits all of it silently.

What to do

  • Update DebugMCP. The fix ships after 1.1.4 — Imperva points to 1.2.0 and later; current is 2.4.1. Because there was no advisory, assume nothing about what your team is running and check the installed extension version directly rather than trusting an absence of alerts.
  • Never set debugmcp.bindHost away from loopback. The maintainers’ own warning text is unusually blunt about this. If you are port-forwarding into a container, forward the loopback port; do not bind the debugger to an interface.
  • Audit what is listening on loopback on developer machines. This is the actionable generalization. Enumerate local ports on engineer endpoints and treat every unauthenticated MCP server as an internet-reachable one, because DNS rebinding makes that distinction thinner than it looks.
  • Make Host/Origin validation a review gate for any MCP server you build. Using the SDK is not enough — the protection rides on createMcpExpressApp. If your team hand-rolled an Express instance, the middleware is your responsibility, and stateless transport mode silently removes the handshake that might otherwise have slowed an attacker down.
  • Treat “no CVE, no release note” as a detection gap, not an all-clear. Imperva’s report names no CVE identifier. Version-based vulnerability management sees nothing here. If your SCA tooling is your only signal on agent tooling, you are blind to exactly this class of silent fix.

One more thing deserves saying, because the maintainers’ patch quietly concedes it: Imperva notes that even with header validation in place, an LLM can still be steered by indirect prompt injection into calling start_debugging on a file outside VS Code’s workspace trust — and the fix does not address that. The rebinding hole is closed. The deeper question, of a debugger tool that executes whatever path its agent is talked into supplying, is still open. Locking the front door is progress. It is not the same as deciding who gets to give the agent orders.

Sources: