T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/bitaxe_status.py:70
- Finding
- Unrestricted Network Destination Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/bitaxe_status.py:70-81`, with untrusted destination selection at `scripts/bitaxe_status.py:126-144` **Vulnerability Type**: Server-Side Request Forgery through insufficient destination validation **Risk Level**: Medium ### Vulnerable Code ```python def fetch_bitaxe_status(ip: str) -> dict: """Fetch system info from Bitaxe Gamma API.""" url = f"http://{ip}/api/system/info" try: with urllib.request.urlopen(url, timeout=10) as response: return json.loads(response.read().decode('utf-8')) except urllib.error.URLError as e: raise ConnectionError(f"Failed to connect to Bitaxe at {ip}: {e}") except json.JSONDecodeError as e: raise ValueError(f"Invalid JSON response: {e}") ``` The destination is obtained from a command-line argument, configuration file, or environment variable and passed directly to the network function: ```python # Determine which IP to use (priority: arg > config file > env var) ip = args.ip if not ip: ip = get_saved_ip() if not ip: parser.error( "No IP provided. Either:\n" " - Pass IP as argument: bitaxe_status.py <IP>\n" " - Save IP to config: bitaxe_status.py --set-ip <IP>\n" " - Set BITAXE_IP environment variable" ) source = "config file" if load_config().get('bitaxe_ip') else "environment variable" print(f"📡 Using Bitaxe IP from {source}: {ip}\n") # Fetch and display status try: data = fetch_bitaxe_status(ip) if args.format == "json": print(json.dumps(data, indent=2)) else: print(format_text(data)) ``` ### Technical Analysis Although the variable is described as an IP address, no validation ensures that it is an IP literal, belongs to an approved private subnet, or identifies a Bitaxe device. The value is interpolated directly into an HTTP URL and passed to `urllib.request.urlopen()`. Consequently, anyone able to ...[truncated 2630 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Validate the destination as an IP address** - Use `ipaddress.ip_address()` rather than accepting an arbitrary URL or hostname. - Reject values containing schemes, credentials, ports, paths, queries, or fragments. - If ports are required, parse the host and port separately and allow only expected ports. 2. **Apply an explicit network allowlist** - Restrict destinations to the subnet or exact addresses where Bitaxe devices are expected. - Reject loopback, link-local, multicast, unspecified, reserved, and public addresses unless explicitly authorized. - Explicitly block cloud metadata addresses such as `169.254.169.254`. 3. **Control redirects** - Disable automatic redirects, or validate every redirect target using the same destination policy before following it. - Impose a small redirect limit. 4. **Construct URLs only from validated components** - Do not interpolate unrestricted input into a complete URL authority. - Use a validated IP literal and a fixed API path. - Enclose validated IPv6 literals in brackets when constructing the URL. 5. **Limit response handling** - Set a maximum response size before reading the body. - Verify the HTTP status and expected content type. - Validate the returned JSON structure against expected Bitaxe fields before displaying it. 6. **Harden transport where supported** - Prefer HTTPS when the target device supports it. - If only HTTP is supported, document that responses can be intercepted or modified by systems on the local network. ]]>
