T09 · Insecure Skill Coding Practices
- Location
fetch_site.py:67- Finding
Unrestricted Remote URLs Enable Server-Side Request Forgery and Potential Content Disclosure
- Content
View full analysis
Vulnerability Details
File Location:
fetch_site.py:67-87, 117-127, 224-238;push_card.py:178-204;send_feishu_api.py:267-274, 400-423
Vulnerability Type: Server-Side Request Forgery (SSRF) with a potential external disclosure path
Risk Level: HighComplete Code Snippet
python # fetch_site.py:67-87 for c in candidates: try: xml = http_get(c, timeout=timeout) # 先判 sitemap 索引再取 <loc>:索引里的 <loc> 是子 sitemap 地址而不是页面, # 必须抓子 sitemap 展开(支持一层嵌套索引) if '<sitemapindex' in xml.lower(): urls = [] for sub in LOC_RE.findall(xml)[:25]: try: sub_xml = http_get(sub, timeout=timeout) if '<sitemapindex' in sub_xml.lower(): for sub2 in LOC_RE.findall(sub_xml)[:25]: try: leaf = http_get(sub2, timeout=timeout) if '<sitemapindex' not in leaf.lower(): urls += [norm_url(u, base_url) for u in LOC_RE.findall(leaf)] except Exception: continue else: urls += [norm_url(u, base_url) for u in LOC_RE.findall(sub_xml)] except Exception: continue if urls: return urls, cpython # fetch_site.py:117-127 def keep(url, base_url, include, exclude): p = urllib.parse.urlsplit(url).path if p in ('', '/'): return False for e in exclude: if p == e.rstrip('/') or p.startswith(e.rstrip('/') + '/'): return False if include: return any(p == i.rstrip('/') or p.startswith(i.rstrip('/') + '/') for i in include) return Truepython # fetch_site.py:224-238 for i, u in enumerate(urls, 1): body, real = fetch_body(u, args.body_suffix, args.timeout) if body is None: failed.append( ...[truncated 5333 chars]- Remediation
View remediation
Remediation Suggestions
-
Introduce a single hardened URL-validation function and apply it to:
- initial sitemap URLs;
- every nested sitemap
<loc>; - every page URL;
- every image URL;
- every redirect destination.
-
Permit only
httpandhttpsschemes. -
By default, require all sitemap, page, and image URLs to remain on the exact origin explicitly selected by the user. Require separate confirmation before allowing additional origins.
-
Resolve hostnames before connecting and reject all addresses in:
- loopback ranges;
- RFC 1918 private ranges;
- link-local ranges;
- multicast and reserved ranges;
- IPv6 unique-local and link-local ranges;
- known cloud metadata destinations.
-
Revalidate after every redirect and protect against DNS rebinding by connecting to the validated resolved address or otherwise binding validation to the actual connection.
-
For image downloads:
- enforce a strict maximum response size;
- validate
Content-Type; - verify image magic and decode the file with a trusted image library;
- reject non-image responses before upload;
- avoid forwarding raw internal response bytes to external services.
-
Add regression tests covering nested sitemap SSRF, cross-origin sitemap pages, redirects to private addresses, IPv4/IPv6 private addresses, and Feishu remote-image URLs.
-
