# Vulnerability Summary ## Vulnerability Overview - **Title**: fix(security): refuse to start API server on non-localhost without auth #6477 - **Description**: The API server (`gateway/platform/api_server.py`) allows unauthorized access when `API_SERVER_KEY` is not configured. The default bind address is `127.0.0.1`, which restricts access to local connections; however, if the host is changed to `0.0.0.0` or any other non-loopback address and the API key is not set, the API server is exposed to unauthorized network clients, including full terminal command execution capabilities. ## Impact Scope - **Affected Component**: `gateway/platform/api_server.py` - **Specific Impact**: When `API_SERVER_KEY` is not configured, the API server can start on non-local addresses and allow unauthorized access, leading to potential security risks. ## Remediation - **Fix Measures**: - Added a `_is_localhost()` static method to detect loopback addresses (`127.x.x.x`, `localhost`, `::1`) using `ipaddress.ip_address()` and `ip_loops`. - Added a startup guard in `connect()` that refuses to bind to non-local addresses when no API key is present, logging a critical message with remediation instructions. - Preserved the local binding behavior without authentication for local development. ### Test Plan - **Test Cases**: - All 106 tests passed (94 existing + 12 new). - Verified that the server refuses to start and returns `False` when binding to `0.0.0.0` without an API key. - Verified that the server starts normally when binding to `127.0.0.1` without an API key. - Verified that the server starts normally when binding to `0.0.0.0` with an API key. - Existing authentication tests (valid key, invalid key, missing header) continue to pass. ### Code Changes - **File**: `gateway/platform/api_server.py` - **New Method**: ```python def _is_localhost(address): """Check if the given address is a localhost address.""" import ipaddress ip_loops = [ ipaddress.ip_address('127.0.0.1'), ipaddress.ip_address('::1'), ipaddress.ip_address('localhost'), ] try: addr = ipaddress.ip_address(address) return addr in ip_loops except ValueError: return False ``` - **Startup Guard**: ```python if not self._is_localhost(host) and not api_key: raise RuntimeError( "Refusing to bind to non-localhost address without API key. " "Set API_SERVER_KEY or use localhost binding." ) ``` ### Test File - **File**: `tests/gateway/test_api_server.py` - **New Tests**: ```python def test_localhost_no_key(): """Test that localhost binding without key succeeds.""" # Test code here def test_non_localhost_no_key(): """Test that non-localhost binding without key fails.""" # Test code here def test_non_localhost_with_key(): """Test that non-localhost binding with key succeeds.""" # Test code here ```