T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/converter.py:64
- Finding
- Server-Side Request Forgery Through Inadequate Music URL Validation## Vulnerability Details **File Location**: `scripts/converter.py`, lines 64–67 and 77 **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```python def identify_platform(self, url): self.logger.debug(f"Identifying platform for URL: {url}") for platform_id, info in self.platforms.items(): for pattern in info["patterns"]: if re.search(pattern, url): self.logger.info(f"Identified platform: {platform_id}") return platform_id ``` The accepted URL is subsequently requested with redirects enabled: ```python response = requests.get( url, headers=headers, timeout=10, allow_redirects=True ) ``` ### Technical Analysis The application determines whether a URL belongs to a supported music platform by searching the entire unparsed URL for an approved-domain pattern. It does not parse the URL and verify that the hostname exactly matches an approved domain or one of its legitimate subdomains. Consequently, an attacker can place an approved domain string in another URL component, such as the query string, path, or user-information section, while directing the actual request to an attacker-selected host. For example: ```text http://169.254.169.254/latest/meta-data/?music.163.com ``` The string `music.163.com` satisfies the regular-expression check, causing the URL to be classified as a NetEase link. `get_song_info()` then sends an HTTP GET request to the link-local metadata address. Redirect processing creates a second exploitation route. Because `allow_redirects=True` is set and redirect destinations are not revalidated, a URL initially hosted on an accepted or attacker-controlled public endpoint can redirect the request to a loopback, private-network, or link-local address. The ten-second timeout limits request duration but does not prevent access to internal resources. ### Attack Path 1. An attacker supplies a URL that contains a supported ...[truncated 1670 chars]
- Remediation
- ## Remediation Suggestions 1. Parse each supplied URL with `urllib.parse.urlsplit()` and reject malformed URLs, credentials in URLs, unexpected ports, and all schemes except `https`. 2. Compare the normalized hostname against an explicit allowlist. Accept only exact approved hosts or intentional subdomains using boundary-safe checks such as: ```python hostname == allowed_domain or hostname.endswith("." + allowed_domain) ``` 3. Resolve the hostname before connecting. Reject every resolved IPv4 and IPv6 address that is loopback, private, link-local, multicast, reserved, or unspecified, using Python's `ipaddress` module. 4. Disable automatic redirects with `allow_redirects=False`. If redirects are required, process them individually, parse and validate every destination, enforce a low redirect limit, and repeat DNS/IP checks before each request. 5. Mitigate DNS rebinding by ensuring the address validated is the address used for the connection. Where possible, enforce outbound restrictions at the network or proxy layer. 6. Permit outbound traffic only to documented music-platform hosts and API endpoints through firewall or egress-proxy rules. 7. Limit response sizes and accepted content types before parsing response bodies. 8. Add automated tests covering approved hosts, deceptive suffixes, user-information tricks, approved strings in paths and queries, encoded hostnames, redirects to internal addresses, IPv4 variants, and IPv6 loopback or link-local targets.
