-
-
Notifications
You must be signed in to change notification settings - Fork 52.7k
Description
Summary
bind: "lan" configuration causes the browser tool (and any Gateway self-connection) to fail with a SECURITY ERROR after the plaintext ws:// block introduced in #20803.
Affected versions
Confirmed broken after commit 9edec67a1 (fix(security): block plaintext WebSocket connections to non-loopback addresses).
Root cause
Two commits are in conflict:
b8c8130ef(fix(gateway): use LAN IP for WebSocket/probe URLs when bind=lan #11448) —fix(gateway): use LAN IP for WebSocket/probe URLs when bind=lan
→buildGatewayConnectionDetailsnow generatesws://192.168.x.x:18789whenbind=lan9edec67a1(fix(security): block plaintext WebSocket connections to non-loopback addresses #20803) —fix(security): block plaintext WebSocket connections to non-loopback addresses
→ All plaintextws://to non-loopback addresses are now rejected
When bind: "lan" is set, localUrl becomes ws://<LAN_IP>:<port>. This passes the #11448 check but is then rejected by the #20803 security guard (isSecureWebSocketUrl returns false for non-loopback IPs).
Relevant code in src/gateway/call.ts:
const preferLan = bindMode === "lan";
const lanIPv4 = preferLan ? pickPrimaryLanIPv4() : undefined;
const localUrl =
preferTailnet && tailnetIPv4
? `${scheme}://${tailnetIPv4}:${localPort}`
: preferLan && lanIPv4
? `${scheme}://${lanIPv4}:${localPort}` // <-- produces ws://192.168.x.x
: `${scheme}://127.0.0.1:${localPort}`;Impact
- Any agent running on the same host as the Gateway with
bind: "lan"cannot connect to its own Gateway via the browser tool or anycallGatewaycode path. - Affected real-world use case: Chi agent on macmini trying to open NotebookLM via the browser tool.
Steps to reproduce
- Set
gateway.bind: "lan"inopenclaw.json - Run any tool that calls
buildGatewayConnectionDetails()(e.g. browser tool opening a URL) - Observe:
SECURITY ERROR: Gateway URL "ws://192.168.x.x:18789" uses plaintext ws:// to a non-loopback address.
Expected behavior
A self-connection from an agent running on the same host should always use ws://127.0.0.1:<port>, regardless of bind mode. The bind setting controls which interface the server listens on — it should not force clients on the same host to use the LAN IP.
Proposed fix
In buildGatewayConnectionDetails, decouple the server bind address from the client connection URL. For self-connections (same host), always prefer loopback:
// localUrl should always use loopback for self-connections.
// bind=lan/tailnet affects the *server* listen interface, not the *client* connect URL.
const localUrl = `${scheme}://127.0.0.1:${localPort}`;If the LAN IP is needed for display purposes (QR code, onboarding hints, etc.), it can be exposed separately without affecting the actual connection URL.
Workaround (temporary)
None available without modifying config in an unsupported way (mode: "remote" + remote.url: "ws://127.0.0.1:<port>" may work but has untested side effects).