T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- .
- Finding
- Unrestricted Website Audit Requests Enable Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/geo_audit.py:67-92` - `scripts/seo_audit.py:52-59` - `scripts/seo_audit.py:215-229` - `scripts/seo_audit.py:249-256` - `scripts/perf_audit.py:55-69` - `scripts/perf_audit.py:130-141` - `scripts/perf_audit.py:183-192` - `scripts/perf_audit.py:348-349` **Vulnerability Type**: Server-Side Request Forgery (SSRF) through user-controlled URLs, sitemap entries, sub-sitemap entries, and redirects **Risk Level**: High ### Vulnerable Code #### `scripts/geo_audit.py:67-92` ```python def fetch(url: str) -> requests.Response: return requests.get( url, headers={"User-Agent": USER_AGENT, "Accept-Encoding": "gzip, br"}, timeout=REQUEST_TIMEOUT, allow_redirects=True, ) def safe_fetch(url: str) -> requests.Response | None: try: return fetch(url) except Exception as exc: print(f" ⚠️ Failed to fetch {url}: {exc}", file=sys.stderr) return None def extract_sitemap_urls(sitemap_url: str) -> list[str]: resp = safe_fetch(sitemap_url) if not resp or resp.status_code != 200: return [] content = resp.text urls = [] if "<sitemapindex" in content.lower(): sub_sitemaps = re.findall(r'<loc>\s*(.*?)\s*</loc>', content) for sub_url in sub_sitemaps: sub_resp = safe_fetch(sub_url) if sub_resp and sub_resp.status_code == 200: urls.extend(re.findall(r'<loc>\s*(.*?)\s*</loc>', sub_resp.text)) else: urls = re.findall(r'<loc>\s*(.*?)\s*</loc>', content) return urls ``` #### `scripts/seo_audit.py:52-59` ```python def fetch(url: str, *, follow_redirects: bool = True) -> requests.Response: """Fetch a URL with standard headers.""" return requests.get( url, headers={"User-Agent": USER_AGENT, "Accept-Encoding": "gzip, br"}, timeout=REQUEST_TIMEOUT, allow_redirects=follow_redirects, ) ``` #### `scripts/seo_audit.py:215- ...[truncated 6593 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Restrict URL schemes** - Parse every URL before use. - Permit only `https` and, where explicitly necessary, `http`. - Reject URLs containing credentials, malformed hostnames, or unsupported schemes. 2. **Restrict requests to the audited origin** - Record the normalized scheme, hostname, and effective port of the approved base URL. - Reject sitemap entries and nested sitemap URLs whose origin differs from the approved origin by default. - If cross-origin resources are required, require explicit user approval or a narrow allowlist. 3. **Block non-public network destinations** - Resolve the destination hostname before connecting. - Reject every resolved IPv4 and IPv6 address classified as loopback, private, link-local, reserved, multicast, or unspecified. - Apply the check to all addresses returned by DNS, not only the first result. - Explicitly block common metadata destinations and IPv4-mapped IPv6 representations. 4. **Validate redirects manually** - Disable automatic redirects with `allow_redirects=False`. - Follow redirects through a bounded loop. - Reapply scheme, origin, hostname, port, and resolved-address validation before every redirect request. - Set a low maximum redirect count. 5. **Protect against DNS rebinding** - Avoid validating one DNS result and allowing the HTTP library to perform an unrelated second resolution. - Bind the validated address to the connection where practical while preserving correct TLS hostname verification. - Revalidate every new connection and redirect. 6. **Harden sitemap processing** - Limit sitemap response size, nesting depth, entry count, and total number of outbound requests. - Require sitemap and page entries to use the audited public origin. - Parse XML with a hardened parser and reject malformed or unexpectedly large documents. 7. **Secure the TLS probe** - Apply the same public-address and origin validation bef ...[truncated 797 chars]
