Repository navigation
Make DevToolsPlugin usable from containers and secure its WebSocket. Closes #2005 - #2008
Merged
waldekmastykarz merged 5 commits intoOct 27, 2026
Merged
Conversation
…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>
Contributor
There was a problem hiding this comment.
🔵 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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2005
Makes
DevToolsPluginwork 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
portsetting (default0): listen on a fixed port so it can be published from the container.0keeps the current behavior and picks a random free port.launchBrowsersetting (defaulttrue): whenfalse, 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:127.0.0.1. It now binds to the proxy's IP address.0.0.0.0and::map to the HttpListener*prefix, while the URL still points DevTools at127.0.0.1, which is where published or forwarded ports arrive. The Docker image already runs with--ip-address 0.0.0.0.IProxyConfiguration. So the inspector now starts inOptionsLoadedinstead ofInitializeAsync, which makes it honor--ip-address. The existingIsProxyCommandgate is kept.ws://127.0.0.1:<port>and read intercepted traffic. Now:--inspect. Connections must use the/<token>path, and both the launched URL and the logged URL include it.Originheader must be a DevTools frontend:devtools://devtools,http://localhost:9222, orhttp://127.0.0.1:9222. A missingOriginis rejected; both real DevTools frontends send one, so there's no reason to allow it.403and a warning in the log. The token isn't logged.devtoolspluginschema and the skill docs now cover the two new settings.DevToolsWebSocketServerTestscovers 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 buildpasses with 0 warnings and 0 errors. All 164 tests inDevProxy.Integration.Testspass.launchBrowser: false: thedevtools://URL with a token is logged. Handshake checks with curl:101403https://evil.example.com,http://localhost:3000, or noOrigin:403http://localhost:9222/...frontend connected.devtools://frontend opened in Edge Dev: connected, which confirms it sends an allowedOrigin.mcr.microsoft.com/dotnet/aspnet:10.0with--ip-address 0.0.0.0and-p 19229:19229.*:19229.101/403) held through the published port.devtools://URL, connected to the container.Notes
*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.