T09 · Insecure Skill Coding Practices
- Location
poly-resolution-tracking/scripts/scrape_source.py:48- Finding
Unrestricted resolution-source fetching enables server-side request forgery
- Content
View full analysis
str: """Fetch URL content as string with retry.""" for attempt in range(max_retries): try: req = urllib.request.Request(url, headers=HEADERS) with urllib.request.urlopen(req, timeout=30) as resp: return resp.read().decode("utf-8", errors="replace") ``` The monitor automatically extracts URLs from market descriptions and passes them to the unrestricted fetch function: ```python # Generic URL extraction urls = re.findall(r'https?://[^\s<>"]+', description) if urls: return { "type": "generic_url", "url": urls[0], } ``` ```python url = source.get("url", "") if source_type == "arena_leaderboard": return scrape_source(url, "arena_leaderboard") elif source_type == "generic_url" and url: return scrape_source(url, "generic") ``` The same implementation pattern exists in the corresponding `poly-resolution-tracking-zh` scripts. ### Technical Analysis The fetch function passes an externally derived URL directly to `urllib.request.urlopen`. It does not: - Restrict requests to HTTPS. - Maintain an allowlist of approved resolution-source domains. - Resolve and reject loopback, private, link-local, multicast, reserved, or cloud-metadata addresses. - Revalidate the destination after redirects. - Limit the response body size. - Prevent DNS rebinding between validation and connection. The URL can be provided directly through `scrape_source.py --url`, and the monitoring workflow can also obtain it from an untrusted Polymarket market description. This creates a reachable SSRF primitive rather than merely an ...[truncated 1491 chars]- Remediation
View remediation
