fix(security): block plaintext WebSocket connections to non-loopback addresses#20803
Conversation
abbdbb3 to
126dfff
Compare
…addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519
Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
2395781 to
a320b26
Compare
|
@thewilloftheshadow I think this should be good to merge |
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
|
You're using the wrong check. "localhost" can point to anything, it's just a hostname that's resolved like any other. The real check you want is if the IP address the hostname resolves to is that of a local interface. And in that case, any interface will do. Traffic to a host's own addresses will never leave the machine. Traffic to whatever "localhost" resolves could travel around the world twice. Aside from that, in my personal opinion, by default a check whether the address is in the broadcast domain of any interface would be the more sensible default. Most network setups won't use a prehistoric network hub but a switch---i.e. direct traffic within a broadcast domain is only visible to the two machines communicating and the switch(es). As installations also are very likely to run in a LAN that is either controlled or trusted by the owner of the machine, packet sniffing by the first switch is a very rare and special attack vector---who plugs a machine into a network port when they don't trust the operator? People who are aware enough to properly secure their machine. Side note: It is a major pain to set up SSL certs for machines that only have an address in the private IP address range. And not only that, it opens up the SSL connections to outside attacks---the DNS provider (and there are not many that allow private IPs and access to the records needed to get a cert) can easily change their address resolution and then someone else easily can get a cert for that hostname. With that, they can redirect local traffic over the internet and even keep it SSL secured. This makes SSL to private addresses less secure than unencrypted local connections that cannot be affected by outside forces. |
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
When bind=lan or bind=tailnet, buildGatewayConnectionDetails() was generating localUrl with the LAN/tailnet IP (e.g. ws://192.168.x.x). The security check added in openclaw#20803 then rejected these as plaintext ws:// to non-loopback addresses. Root cause: bind mode controls which interface the *server* listens on, but was incorrectly also driving the *client* connection URL for agents running on the same host. Fix: localUrl now always uses ws://127.0.0.1 (loopback). LAN and tailnet IPs remain available in lanIPv4/tailnetIPv4 for display purposes (QR codes, onboarding hints, urlSource labels) but are no longer used as the actual connection target. Fixes openclaw#22047
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test. (cherry picked from commit 9edec67) # Conflicts: # src/commands/gateway-status.test.ts # src/gateway/call.test.ts # src/gateway/client.test.ts # src/gateway/net.test.ts # src/tui/gateway-chat.test.ts
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test. (cherry picked from commit 9edec67) # Conflicts: # src/commands/gateway-status.test.ts # src/gateway/call.test.ts # src/gateway/call.ts # src/gateway/client.test.ts # src/gateway/net.test.ts # src/tui/gateway-chat.test.ts
…addresses (openclaw#20803) * fix(security): block plaintext WebSocket connections to non-loopback addresses Addresses CWE-319 (Cleartext Transmission of Sensitive Information). Previously, ws:// connections to remote hosts were allowed, exposing both credentials and chat data to network interception. This change blocks ALL plaintext ws:// connections to non-loopback addresses, regardless of whether explicit credentials are configured (device tokens may be loaded dynamically). Security policy: - wss:// allowed to any host - ws:// allowed only to loopback (127.x.x.x, localhost, ::1) - ws:// to LAN/tailnet/remote hosts now requires TLS Changes: - Add isSecureWebSocketUrl() validation in net.ts - Block insecure connections in GatewayClient.start() - Block insecure URLs in buildGatewayConnectionDetails() - Handle malformed URLs gracefully without crashing - Update tests to use wss:// for non-loopback URLs Fixes openclaw#12519 * fix(test): update gateway-chat mock to preserve net.js exports Use importOriginal to spread actual module exports and mock only the functions needed for testing. This ensures isSecureWebSocketUrl and other exports remain available to the code under test.
Summary
Fixes #12519 - CWE-319: Cleartext Transmission of Sensitive Information (CVSS 9.8)
This PR blocks ALL plaintext
ws://WebSocket connections to non-loopback addresses, protecting both credentials and chat data from network interception.Security Policy
wss://any hostws://127.0.0.1,ws://localhost,ws://[::1]ws://LAN/tailnet/remoteKey Changes
src/gateway/net.ts: AddedisSecureWebSocketUrl()to validate WebSocket URL securitysrc/gateway/client.ts: Block insecure connections at connection time (catches device tokens loaded dynamically)src/gateway/call.ts: Block insecure URLs during config/URL resolution (all code paths)Why Block Without Checking Credentials?
Test plan
GatewayClientsecurity checks (4 tests)buildGatewayConnectionDetailsblocking (5 tests)wss://for non-loopback URLsGreptile Summary
This PR addresses a critical security vulnerability (CWE-319: Cleartext Transmission of Sensitive Information, CVSS 9.8) by blocking plaintext WebSocket connections to non-loopback addresses. The implementation adds
isSecureWebSocketUrl()validation that allowswss://to any host andws://only to loopback addresses (localhost, 127.x.x.x, ::1).Key changes:
isSecureWebSocketUrl()function insrc/gateway/net.tswith proper URL parsing and error handlingGatewayClient.start()andbuildGatewayConnectionDetails()to catch all code pathswss://for non-loopback URLs and enable TLS in config where neededwss://or SSH tunnelingThe fix correctly implements defense in depth by blocking at both connection initialization and URL resolution, handles malformed URLs gracefully, and protects both credentials and chat data from interception.
Confidence Score: 5/5
Last reviewed commit: 9952d0e
(2/5) Greptile learns from your feedback when you react with thumbs up/down!