Skip to content

Harden MCP HTTP endpoint: loopback bind + Host/Origin validation#78

Open
ozzafar wants to merge 2 commits into
mainfrom
ozzafar/resolve_icms
Open

Harden MCP HTTP endpoint: loopback bind + Host/Origin validation#78
ozzafar wants to merge 2 commits into
mainfrom
ozzafar/resolve_icms

Conversation

@ozzafar
Copy link
Copy Markdown
Contributor

@ozzafar ozzafar commented May 24, 2026

Fixes ICM 31000000603080 (unauthenticated debugger access via 0.0.0.0 bind) and ICM 31000000611073 (DNS rebinding via missing Host header validation), both reported by MSRC against src/debugMCPServer.ts.

Background

The DebugMCP HTTP server exposes powerful, unauthenticated debugger primitives (evaluate_expression, start_debugging, …). MSRC reported two composable vulnerabilities:

  • 603080 — LAN exposure. app.listen(this.port, callback) was called with no host argument, so Node bound to all interfaces (0.0.0.0). Any host on the same Wi‑Fi / co‑working LAN could POST /mcp and invoke evaluate_expression('import("os").system(...)') for RCE the debuggee, or start_debugging against a UNC path.
  • 611073 — DNS rebinding → RCE. Even with a loopback bind, a malicious page on attacker.example (short‑TTL DNS flipped to 127.0.0.1) can reach the local server via the victim's browser. The server didn't inspect the Host header, so the rebound request hit start_debugging with a UNC fileFullPath and spawned attacker‑controlled code under the victim's user. PoC video from the finder confirmed it in Firefox.

Fixes

  • Bind to loopback by default. The HTTP server now binds to 127.0.0.1 instead of all interfaces, so it is unreachable from other hosts on the network.
  • Reject non‑loopback Host headers. Requests whose Host header doesn't name a loopback address (localhost, 127.0.0.1, [::1], with or without port) are rejected with HTTP 403 before any MCP handler runs — neutralizing DNS‑rebinding attacks even if the bind is later widened.
  • Reject non‑loopback Origin headers. When Origin is present (browser‑originated requests), it must also be loopback; absent Origin is allowed so non‑browser MCP clients keep working.
  • Explicit opt‑in for LAN exposure. A new debugmcp.bindHost setting lets advanced users widen the bind, with a marketplace warning describing the risk and a startup log warning when the value is non‑loopback.
  • Regression tests. New security test suite covers the loopback / IPv6 / port‑suffix / attacker / LAN cases for the header validators, asserts the server refuses TCP on a non‑loopback interface, and asserts live POST /mcp requests with attacker Host / Origin headersreceive 403.
  • Documented security model. README now describes the loopback‑only default, the opt‑in bindHost, and the Host/Origin allow‑list, so the documented contract matches the implementation.

Validation

  • npm run compile ✅
  • npm run lint ✅
  • npm test — not run locally because a CodeSetup-stable-* installer is currently holding the vscode-updating Inno Setup mutex and @vscode/test-cli cannot launch its bundled VS Code. CI will exercise the new security suite.

Manual repro against the fixed build

Rebinding-style request — now rejected:
curl -i -X POST "http://127.0.0.1:3001/mcp"
-H "Host: attacker.example"
-H "Content-Type: application/json"
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
→ HTTP/1.1 403 Forbidden
{"jsonrpc":"2.0","error":{"code":-32000,"message":"Forbidden: Host header is not a loopback address"},"id":null}

LAN-style probe — connection now refused:
nmap -p 3001
→ 3001/tcp closed

@github-actions
Copy link
Copy Markdown

✅ Extension Build Successful!

📦 VSIX artifact is ready for download

👉 View artifacts

Scroll down to the "Artifacts" section and download extension-vsix

To install: In VS Code, run Extensions: Install from VSIX... and select the downloaded file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant