T09 · Insecure Skill Coding Practices
Error
- Location
- lib/router.py:36
- Finding
- Unrestricted URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `lib/router.py:36-51`, `lib/article.py:74-83`, `lib/article.py:101-110`, `lib/article.py:262-284` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code `lib/router.py:36-51`: ```python def route(url): """Parse URL and return routing config dict.""" parsed = urlparse(url) domain = parsed.hostname or "" # Exact match if domain in ROUTE_TABLE: return dict(ROUTE_TABLE[domain]) # Subdomain matching (e.g., *.feishu.cn) for key, config in ROUTE_TABLE.items(): if domain.endswith("." + key): return dict(config) return dict(_DEFAULT) ``` `lib/article.py:74-83`: ```python cmd_md = ["scrapling", "extract", "get", url, md_file] cmd_html = ["scrapling", "extract", "get", url, html_file] if selector: cmd_md += ["-s", selector] cmd_html += ["-s", selector] print(f"[*] Scrapling GET: {url}") r1 = subprocess.run(cmd_md, capture_output=True, text=True, timeout=60) r2 = subprocess.run(cmd_html, capture_output=True, text=True, timeout=60) ``` `lib/article.py:262-284`: ```python def _download_image(url, local_path, referer=None): """Download image with appropriate headers. Returns True on success.""" try: req = urllib.request.Request(url) req.add_header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36") if referer: req.add_header("Referer", referer) with urllib.request.urlopen(req, timeout=30) as resp: data = resp.read() if len(data) < 100: # Too small, likely an error return False with open(local_path, "wb") as f: f.write(data) return True except Exception as e: print(f"[!] Image download failed: {url} - {e}") return False ``` ### Technical Analysis The routing function accepts arbitrary URL input and routes every unreco ...[truncated 2567 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only explicit `http` and `https` schemes. 2. Require a nonempty hostname and reject embedded credentials and malformed ports. 3. Resolve the hostname before connecting and reject every address in loopback, private, link-local, reserved, multicast, and unspecified ranges. 4. Explicitly deny known metadata destinations, including link-local metadata addresses. 5. Disable redirects or validate the scheme, hostname, DNS result, and resolved IP after every redirect. 6. Protect against DNS rebinding by connecting only to previously validated resolved addresses where supported. 7. Apply the same validation to initial article URLs, image URLs, and every browser navigation or subresource-fetch path. 8. Consider an allowlist of supported public platforms rather than applying a generic fetcher to every unknown host. 9. For generic article images, enforce an origin allowlist or require explicit user approval before contacting a different host. 10. Run browser and downloader components inside a sandbox with outbound network restrictions that prevent access to internal and metadata networks. ]]>
