T09 · Insecure Skill Coding Practices
Error
- Location
- lib/browser_core.py:31
- Finding
- Unrestricted CDP Endpoint Enables SSRF and Attacker-Controlled WebSocket Connections## Vulnerability Details **File Locations**: - `lib/browser_core.py:31,45-50,55-61` - `lib/browser_core_fixed.py:23,38-43,47-58` **Vulnerability Type**: Server-Side Request Forgery and untrusted WebSocket endpoint connection **Risk Level**: High ### Vulnerable Code `lib/browser_core.py`: ```python self.cdp_http_url = self.config.get( "cdp_http_url", "http://localhost:18800/json" ) def _get_websocket_url(self) -> Optional[str]: """Get WebSocket URL from CDP HTTP endpoint.""" import requests try: response = requests.get(self.cdp_http_url, timeout=5) targets = response.json() for target in targets: if target.get("type") == "page": return target["webSocketDebuggerUrl"] return None except Exception as e: logger.error(f"Failed to get WebSocket URL: {e}") return None def connect(self) -> bool: """Connect to browser via WebSocket.""" ws_url = self._get_websocket_url() if not ws_url: logger.error("No WebSocket URL available") return False try: self.ws = websocket.create_connection(ws_url, timeout=self.timeout) ``` `lib/browser_core_fixed.py`: ```python self.cdp_http_url = self.config.get( "cdp_http_url", "http://localhost:18800/json" ) def _get_websocket_url(self) -> Optional[str]: """Get WebSocket URL from CDP HTTP endpoint.""" try: response = requests.get(self.cdp_http_url, timeout=5) targets = response.json() for target in targets: if target.get("type") == "page": return target["webSocketDebuggerUrl"] return None except Exception as e: logger.error(f"Failed to get WebSocket URL: {e}") return None def connect(self) -> bool: """Connect to browser via WebSocket with proper headers.""" ws_url = self._get_websocket_url() i ...[truncated 3064 chars]
- Remediation
- ## Remediation Suggestions 1. Restrict CDP access to an explicit allowlist. If only local OpenClaw CDP is supported, require exactly an approved loopback host and port, such as `http://127.0.0.1:18800/json`. 2. Reject user-info components, fragments, non-HTTP schemes, unexpected ports, and malformed URLs. 3. Resolve the hostname before connecting and reject unspecified, private, loopback, link-local, multicast, and reserved addresses unless a specific address is explicitly approved. 4. Disable automatic redirects with `allow_redirects=False`, or validate every redirect destination before following it. 5. Set a maximum response size and verify the response content type and expected JSON structure. 6. Validate `webSocketDebuggerUrl` independently. Permit only `ws` or `wss` and require its resolved host and port to match the approved CDP service. 7. Prefer deriving the WebSocket destination from a trusted endpoint rather than accepting an arbitrary host from response data. 8. Apply outbound network controls so the process cannot access cloud metadata or unrelated internal services. 9. Add tests covering IPv4, IPv6, encoded loopback addresses, DNS rebinding, redirect-based bypasses, and a JSON response containing a remote WebSocket URL.
