-
-
Notifications
You must be signed in to change notification settings - Fork 69.3k
normalizeCdpWsUrl fails to rewrite ws://0.0.0.0 from containerized browsers #17752
Description
Description
When using a remote/containerized browser (e.g., browserless via Docker), Chrome reports webSocketDebuggerUrl: "ws://0.0.0.0:3000" in its /json/version response. normalizeCdpWsUrl() is supposed to rewrite the WebSocket URL to the external host:port from the configured cdpUrl, but it only does this when isLoopbackHost(ws.hostname) returns true.
0.0.0.0 (and ::) are not considered loopback by isLoopbackAddress() — this is technically correct for bind semantics, but wrong for CDP URL rewriting. These are wildcard bind addresses that mean "all interfaces inside the container," which has the same semantic intent as loopback: "this is my internal address, rewrite it."
Steps to Reproduce
- Run browserless (or any headless Chrome) in a Docker container with port mapping (e.g.,
18850:3000) - Configure OpenClaw with a remote browser profile:
{ "browser": { "defaultProfile": "browserless", "profiles": { "browserless": { "cdpUrl": "http://192.168.1.202:18850?token=...", "color": "#FF6600" } } } } - Try to use the browser tool (screenshot, navigate, etc.)
Expected Behavior
normalizeCdpWsUrl("ws://0.0.0.0:3000", "http://192.168.1.202:18850?token=...") should rewrite to ws://192.168.1.202:18850?token=... — the same behavior as if Chrome had reported ws://127.0.0.1:3000.
Actual Behavior
The function sees 0.0.0.0 is not loopback, skips the rewrite, and OpenClaw tries to connect to ws://0.0.0.0:3000 literally. This fails, and the browser service reports "port is in use but not by openclaw."
Root Cause
In src/browser/cdp.ts, normalizeCdpWsUrl():
if (isLoopbackHost(ws.hostname) && !isLoopbackHost(cdp.hostname)) {
ws.hostname = cdp.hostname;
// ...
}And in src/gateway/net.ts, isLoopbackAddress() explicitly excludes 0.0.0.0:
// 0.0.0.0 and :: are NOT loopbackProposed Fix
Treat 0.0.0.0 and :: as wildcard addresses that need rewriting, alongside loopback:
const isWildcard = ws.hostname === "0.0.0.0" || ws.hostname === "::";
if ((isLoopbackHost(ws.hostname) || isWildcard) && !isLoopbackHost(cdp.hostname)) {This doesn't change isLoopbackAddress (which is correct for its general purpose) — it only adds wildcard handling to the CDP URL rewrite logic where the intent is clear.
Environment
- OpenClaw v2026.2.14
- browserless/chromium 2.38.4 (Chrome 145)
- Docker 28.1.1, Debian 12