T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/search_web.py:63
- Finding
- Server-Side Request Forgery Through Unrestricted URL Fetching<![CDATA[ ## Vulnerability Details **File Location**: `scripts/search_web.py`, lines 63-83 **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```python def fetch_url(url: str) -> dict: """ Fetch and parse a webpage. Args: url: URL to fetch Returns: Dictionary with title, content, and metadata """ headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } try: response = requests.get(url, headers=headers, timeout=15, allow_redirects=True) response.raise_for_status() soup = BeautifulSoup(response.text, 'html.parser') ``` ### Technical Analysis The `fetch_url` function passes a caller-controlled URL directly to `requests.get()` without validating its scheme, hostname, resolved IP address, port, or destination network. Consequently, an attacker who can supply a URL can cause the process to issue HTTP requests to resources reachable from the host running this skill, including: - Loopback services such as `127.0.0.1` or `[::1]`. - Private-network services in RFC 1918 address ranges. - Link-local addresses and potential cloud instance metadata services. - Internal services that are not externally reachable. - Redirect destinations, because `allow_redirects=True` is enabled without revalidating each redirect target. - Hostnames that resolve to prohibited addresses or use DNS rebinding to change their resolution between validation and connection. The response body is extracted and returned in the `content` field, up to 5,000 characters. This makes the issue a response-disclosing SSRF rather than merely a blind SSRF. Although the returned content is truncated, `requests` downloads the response before truncation, so a malicious or unexpectedly large response may also consume excessive memory. ### Attack Path 1. An attacker asks the agent or another caller to fetch an attacker-select ...[truncated 1655 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Restrict accepted schemes to `https`, or to `http` and `https` only when plaintext HTTP is explicitly required. 2. Use an allowlist of approved domains where the use case permits it. A denylist alone is insufficient. 3. Resolve the hostname before connecting and reject every resolved IPv4 and IPv6 address that is loopback, private, link-local, multicast, reserved, unspecified, or otherwise non-global. 4. Disable automatic redirects with `allow_redirects=False`, or inspect and revalidate the scheme, hostname, port, and resolved addresses of every redirect target before following it. 5. Protect against DNS rebinding by ensuring the validated address is the address actually used for the connection. Consider routing requests through a hardened outbound proxy that enforces destination policy. 6. Block cloud metadata addresses and platform-specific internal service ranges at both the application and network layers. 7. Enforce an explicit port policy, preferably limiting requests to ports 80 and 443 unless other ports are required. 8. Use streamed responses and enforce a maximum download size before loading response content into memory. 9. Apply outbound firewall or container-network rules so the skill cannot reach loopback-adjacent services, private networks, metadata endpoints, or other sensitive destinations. 10. Add automated tests covering IPv4, IPv6, alternate address representations, redirect chains, hostname resolution to private addresses, and DNS-rebinding scenarios. ]]>
