T09 · Insecure Skill Coding Practices
- Location
scripts/feed_to_md.py:25- Finding
DNS Rebinding Bypasses SSRF Address Validation
- Content
View full analysis
None: if hostname in {"localhost", "localhost.localdomain"}: raise ValueError(f"{label} uses localhost, which is not allowed") try: addr_info = socket.getaddrinfo(hostname, None) except socket.gaierror as exc: raise ValueError(f"Unable to resolve host: {hostname}") from exc for item in addr_info: ip_raw = item[4][0] ip = ipaddress.ip_address(ip_raw) if ( ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_multicast or ip.is_reserved or ip.is_unspecified ): raise ValueError(f"{label} resolves to a non-public IP address") def validate_feed_url(raw_url: str, label: str = "Feed URL") -> str: parsed = urllib.parse.urlparse(raw_url) if parsed.scheme not in {"http", "https"}: raise ValueError(f"{label} must use http or https") if not parsed.hostname: raise ValueError(f"{label} must include a hostname") hostname = parsed.hostname.strip().lower() validate_public_hostname(hostname, f"{label} host") return parsed.geturl() ``` The validated hostname is subsequently passed to a network client that performs its own DNS resolution: ```python class PublicOnlyRedirectHandler(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): # noqa: D401 redirected_url = urllib.parse.urljoin(req.full_url, newurl) validate_feed_url(redirected_url, "Redirect URL") return super().redirect_request(req, fp, code, msg, headers, newurl) def fetch_xml(url: str, timeout: int = 15) -> bytes: request = urllib.request.Request( ...[truncated 3517 chars]- Remediation
View remediation
