T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/competitor-scraper.py:118
- Finding
- Unrestricted User-Controlled URL Fetching Enables Server-Side Request Forgery## Vulnerability Details **File Location**: `scripts/competitor-scraper.py:118-129`; reachable through `scripts/competitor-scraper.py:247-252` and CLI arguments at `scripts/competitor-scraper.py:280-282` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```python def scrape_generic_reviews(url): """ Generic web scraper for review pages. Looks for common review HTML patterns. """ reviews = [] try: headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' } response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() ``` The vulnerable function is exposed through the following dispatch logic: ```python def scrape_competitor(platform, identifier): if platform == "gumroad": return scrape_gumroad_reviews(identifier) elif platform == "producthunt": return scrape_producthunt_reviews(identifier) elif platform == "url": return scrape_generic_reviews(identifier) else: print(f"Unknown platform: {platform}", file=sys.stderr) return [] ``` User input reaches the function through these arguments: ```python parser.add_argument("--platform", required=True, choices=["gumroad", "producthunt", "url"], help="Platform to scrape") parser.add_argument("--identifier", help="Product identifier (slug or ID)") parser.add_argument("--url", help="Direct URL to scrape") ``` ### Technical Analysis When the `url` platform is selected, the program passes the user-controlled `--url` or `--identifier` value directly to `requests.get()`. It does not validate: - The URL scheme - The destination hostname - The resolved IP address - The destination port - Whether the address is loopback, private, link-local, or reserved - Redirect destinations The `requests` li ...[truncated 2388 chars]
- Remediation
- ## Remediation Suggestions 1. Restrict generic scraping to an explicit allowlist of approved public review domains where feasible. 2. Permit only HTTPS URLs and reject URLs containing embedded credentials. 3. Reject nonstandard destination ports unless explicitly required. 4. Resolve the hostname before connecting and reject every resolved address belonging to loopback, private, link-local, multicast, unspecified, or reserved ranges for both IPv4 and IPv6. 5. Disable automatic redirects with `allow_redirects=False`, or validate every redirect target using the same scheme, hostname, port, and resolved-address controls. 6. Protect against DNS rebinding by ensuring the validated address is the address actually used for the connection. 7. Apply outbound firewall or proxy rules so the Skill can connect only to approved public destinations. 8. Impose response-size limits in addition to the existing timeout. 9. Return a clear validation error before making a request when a destination is not approved. 10. Add automated tests covering loopback, RFC1918 private ranges, IPv6 local addresses, link-local metadata addresses, encoded IP representations, and redirect-based bypasses.
