Skip to content

Make DevToolsPlugin usable from containers and secure its WebSocket. Closes #2005 - #2008

Merged
waldekmastykarz merged 5 commits into
dotnet:mainfrom
waldekmastykarz:devtools-remote-inspection
Oct 27, 2026
Merged

waldekmastykarz merged 5 commits into
dotnet:mainfrom
waldekmastykarz:devtools-remote-inspection

Conversation

@waldekmastykarz

Copy link
Copy Markdown
Collaborator

Closes #2005

Makes DevToolsPlugin work when Dev Proxy runs in a devcontainer, GitHub Codespaces, or an Aspire container. It also closes an existing security gap in the DevTools WebSocket server.

Changes

  • port setting (default 0): listen on a fixed port so it can be published from the container. 0 keeps the current behavior and picks a random free port.
  • launchBrowser setting (default true): when false, the plugin doesn't look for a browser or launch one. Instead it logs the inspector URL for you to paste into Edge or Chrome on the host:
    DevToolsPlugin available at devtools://devtools/bundled/inspector.html?ws=127.0.0.1:<port>/<token>. Open this URL in Microsoft Edge or Google Chrome to inspect requests.
    
  • Bind address: the WebSocket listener used to be hardcoded to 127.0.0.1. It now binds to the proxy's IP address. 0.0.0.0 and :: map to the HttpListener * prefix, while the URL still points DevTools at 127.0.0.1, which is where published or forwarded ports arrive. The Docker image already runs with --ip-address 0.0.0.0.
    • Plugins are initialized before command-line options are applied to IProxyConfiguration. So the inspector now starts in OptionsLoaded instead of InitializeAsync, which makes it honor --ip-address. The existing IsProxyCommand gate is kept.
  • Security: before this change, the WebSocket accepted any path from any origin. Browsers don't apply CORS to WebSockets, so any web page could connect to ws://127.0.0.1:<port> and read intercepted traffic. Now:
    • A random GUID token is generated per run, like Node's --inspect. Connections must use the /<token> path, and both the launched URL and the logged URL include it.
    • The Origin header must be a DevTools frontend: devtools://devtools, http://localhost:9222, or http://127.0.0.1:9222. A missing Origin is rejected; both real DevTools frontends send one, so there's no reason to allow it.
    • Rejected connections get 403 and a warning in the log. The token isn't logged.
  • The v4.0.0 devtoolsplugin schema and the skill docs now cover the two new settings.
  • DevToolsWebSocketServerTests covers the token and origin checks against a real listener, plus the IP-to-host mapping.

With Aspire, publish the port with the built-in .WithHttpEndpoint(targetPort: <port>, name: "devtools"). No changes to the Aspire extension are needed.

Verification

  • dotnet build passes with 0 warnings and 0 errors. All 164 tests in DevProxy.Integration.Tests pass.
  • launchBrowser: false: the devtools:// URL with a token is logged. Handshake checks with curl:
    • Correct token with each allowed origin: 101
    • Wrong or missing token: 403
    • https://evil.example.com, http://localhost:3000, or no Origin: 403
  • Launched-browser flow (Edge Dev, macOS): the http://localhost:9222/... frontend connected.
  • devtools:// frontend opened in Edge Dev: connected, which confirms it sends an allowed Origin.
  • Container: ran the build in mcr.microsoft.com/dotnet/aspnet:10.0 with --ip-address 0.0.0.0 and -p 19229:19229.
    • The listener bound to *:19229.
    • The same handshake results (101/403) held through the published port.
    • Host Edge DevTools, opened on the logged devtools:// URL, connected to the container.

Notes

  • On Windows, HttpListener's * prefix requires a URL ACL or admin rights. If binding fails, the plugin now logs an error instead of failing silently in an unobserved task.

…loses dotnet#2005

- Add `port` setting to listen on a fixed port (0, default, picks a random port)
- Add `launchBrowser` setting; when false, log a devtools:// URL to open manually
- Bind the DevTools WebSocket to the proxy's IP address (0.0.0.0 -> all interfaces)
  and start it after command-line options are applied so --ip-address is honored
- Require a random per-run token in the WebSocket path and only accept
  connections from DevTools frontend origins
- Update the v4.0.0 schema and skill docs; add tests

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@waldekmastykarz
waldekmastykarz requested a review from a team as a code owner October 27, 2026 09:24
Copilot AI balanced review requested due to automatic review settings October 27, 2026 09:24
Comment thread DevProxy.Plugins/Inspection/WebSocketServer.cs Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Exposing intercepted traffic beyond loopback requires final human security and cross-platform compatibility review.

No open issues 🎉

What changed in this PR

Enables host-browser inspection when Dev Proxy runs in a container, addressing #2005, and adds access controls to the DevTools WebSocket.

Changes:

  • Adds configurable ports and optional browser launching, with listener startup deferred until command-line options are applied.
  • Binds to the configured proxy address and requires a per-run token and an allowed DevTools origin.
  • Updates schemas and documentation, and adds integration tests for access checks and address mapping.
File Description
skills/​dev-proxy/​references/​plugin-catalog.md Documents the new plugin settings.
skills/​dev-proxy/​references/​configuration.md Adds port and browser-launch configuration guidance.
schemas/​v4.0.0/​devtoolsplugin.schema.json Defines and validates the new settings.
DevProxy.Plugins/​Inspection/​WebSocketServer.cs Adds configurable binding, token validation, and origin checks.
DevProxy.Plugins/​Inspection/​DevToolsPlugin.cs Supports container-aware startup and tokenized inspector URLs.
DevProxy.Integration.Tests/​DevToolsWebSocketServerTests.cs Tests connection access controls and host mapping.

Review effort: Balanced

waldekmastykarz and others added 3 commits October 27, 2026 10:39
Addresses CodeQL log-injection alert: the Origin header is client-controlled
and the listener may be network-reachable.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
On Windows, HttpListener needs admin rights or a URL ACL for the * prefix,
so with --ip-address 0.0.0.0 the DevTools plugin would otherwise fail where
it previously worked on 127.0.0.1.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@waldekmastykarz
waldekmastykarz merged commit 7e82379 into dotnet:main Oct 27, 2026
6 checks passed
@waldekmastykarz
waldekmastykarz deleted the devtools-remote-inspection branch October 27, 2026 10:03
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.

Use of DevToolsPlugin in a devcontainer?

3 participants