T09 · Insecure Skill Coding Practices
- Location
scripts/seo_quick_audit.py:40- Finding
Arbitrary URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
FetchResult: def fetch_via_urllib() -> FetchResult: req = urllib.request.Request(url, headers={"User-Agent": user_agent}) ctx = ssl.create_default_context() start = time.perf_counter() try: with urllib.request.urlopen(req, timeout=timeout_s, context=ctx) as resp: raw = resp.read() ``` The curl fallback also follows redirects without validating their destinations: ```python cmd = [ "curl", "-sS", "-L", "--max-time", str(timeout_s), "-A", user_agent, "-w", sentinel + "%{http_code}\n%{url_effective}\n", url, ] proc = subprocess.run(cmd, capture_output=True, text=True) ``` Only the scheme is normalized before the request: ```python def audit(url: str, *, timeout_s: int, user_agent: str, check_robots: bool, check_sitemap: bool) -> dict[str, Any]: if not url.startswith(("http://", "https://")): url = "https://" + url main = fetch(url, timeout_s=timeout_s, user_agent=user_agent) ``` The verifier contains the same unrestricted behavior: ```python head_cmd = [ "curl", "-sS", "-o", "/dev/null", "-w", "%{http_code}|%{redirect_url}|%{url_effective}", "-L", "--max-redirs", "5", "--connect-timeout", str(timeout), "--max-time", str(timeout + 5), url ] proc = subprocess.run(head_cmd, capture_output=True, text=True, timeout=timeout + 10) ``` ### Technical Analysis The audit and verification functions accept URLs derived from command-line arguments, prospect JSON, reports, or directory data. They permit arbitrary HTTP and HTTPS destinations and follow redirects. They do not reject: - Loop ...[truncated 1974 chars]- Remediation
View remediation
