T09 · Insecure Skill Coding Practices
- Location
scripts/scan_competitors.py:21- Finding
Unrestricted Request Destinations Enable Server-Side Request Forgery
- Content
View full analysis
Vulnerability Details
File Location:
scripts/scan_competitors.py, lines 21-40 and 259-265
Vulnerability Type: Server-Side Request Forgery through unrestricted user-controlled domains and redirects
Risk Level: HighVulnerable Code:
python class GEOScanner: """Scan website for GEO signals.""" def __init__(self, domain, timeout=10): self.domain = domain.replace('https://', '').replace('http://', '').rstrip('/') self.base_url = f"https://{self.domain}" self.timeout = timeout self.results = { 'domain': self.domain, 'technical': {}, 'content': {}, 'entity': {}, 'citation': {} } def fetch(self, path=''): """Fetch URL.""" url = urljoin(self.base_url, path) try: resp = requests.get(url, timeout=self.timeout, allow_redirects=True) return resp except Exception as e: return Nonepython domains = [args.brand] + [c.strip() for c in args.competitors.split(",")] results = [] for domain in domains: scanner = GEOScanner(domain) result = scanner.run_full_scan() results.append(result)Technical Analysis
Values supplied through
--brandand--competitorsare directly converted into outbound HTTPS request targets. The code does not validate that a supplied hostname resolves to a publicly routable address. It therefore permits loopback, private, link-local, reserved, and internal DNS destinations.The request also uses
allow_redirects=True. Even if an initial hostname were validated as public, an attacker-controlled public endpoint could redirect the scanner to an internal address. No validation is performed for redirect destinations or after DNS resolution.The scanner sends requests to numerous fixed paths, including
/,/llms.txt,/robots.txt, ` ...[truncated 1719 chars]- Remediation
View remediation
Remediation Suggestions
- Parse targets using
urllib.parserather than modifying strings withreplace(). - Accept only well-formed hostnames with an explicitly permitted scheme, preferably HTTPS.
- Resolve every hostname before connecting and reject all loopback, private, link-local, multicast, reserved, and unspecified IPv4 and IPv6 addresses using Python's
ipaddressmodule. - Disable automatic redirects or validate the hostname and resolved addresses of every redirect destination before following it.
- Guard against DNS rebinding by ensuring the address used for the connection remains within the validated set.
- Apply an outbound firewall or proxy allowlist so the scanner can reach only public web destinations.
- Reject embedded credentials, unexpected ports, malformed hostnames, and ambiguous URL syntax.
- Add tests covering loopback addresses, RFC 1918 networks, IPv6 local addresses, internal DNS names, encoded IP representations, and public-to-private redirects.
- Return a clear validation error instead of silently treating blocked destinations as failed scans.
- Parse targets using
