T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/generate.py:148
- Finding
- Unrestricted Product and Image URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate.py:148-198` **Vulnerability Type**: Server-Side Request Forgery (SSRF) through unrestricted URL fetching **Risk Level**: High ### Vulnerable Code ```python def fetch_product_image(client: httpx.Client, product_url: str, dest: Path) -> bool: """Try to find and download the main product image from a product page.""" try: from bs4 import BeautifulSoup except ImportError: print(" ⚠ beautifulsoup4 not available for product image extraction", flush=True) return False print(" Fetching product page for main image...", flush=True) try: headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Accept": "text/html,*/*", } response = client.get(product_url, headers=headers, follow_redirects=True, timeout=20.0) if response.status_code != 200: print(f" ✗ Could not fetch product page ({response.status_code})", flush=True) return False soup = BeautifulSoup(response.text, "html.parser") # Strategy 1: og:image meta tag (most reliable) og_img = soup.find("meta", property="og:image") if og_img and og_img.get("content"): img_url = urljoin(product_url, og_img["content"]) print(f" Found og:image: {img_url[:80]}...", flush=True) if download_to_file(client, img_url, dest): return True # Strategy 2: Large images in the page images = soup.find_all("img") candidates = [] for img in images: src = img.get("src") or img.get("data-src") or img.get("data-lazy-src") if not src: continue src = urljoin(product_url, src) # Skip tiny images, icons, tracking pixels width = img.get("width", "0") height = img.get("height", "0") try: w = in ...[truncated 3826 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Allow only `https` URLs unless plain HTTP is explicitly required and justified. 2. Reject URLs containing embedded credentials, malformed hostnames, unexpected ports, or non-HTTP schemes. 3. Resolve the hostname before connecting and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges. 4. Explicitly block common cloud metadata destinations, including link-local metadata addresses. 5. Disable automatic redirects or validate the scheme, hostname, port, and resolved address of every redirect target before following it. 6. Protect against DNS rebinding by ensuring that the address actually used for the connection is an approved public address. 7. Apply the same validation to `product_url`, `og:image`, every `img` source, and any user-provided remote image URL. 8. Use an outbound proxy or network sandbox that permits access only to public Internet destinations and the documented ComfyDeploy API. 9. Enforce a strict maximum response size while streaming rather than loading an unbounded response into memory. 10. Verify image content using file signatures and an image decoder instead of trusting the `Content-Type` header or response length. 11. Require explicit user confirmation before uploading automatically fetched content to ComfyDeploy. ]]>
