T09 · Insecure Skill Coding Practices
- Location
src/poe_media.py:32- Finding
Unrestricted Media URL Fetch Enables Server-Side Request Forgery and Resource Exhaustion
- Content
View full analysis
bool: """Download *url* to *output_path*. Returns True on success.""" try: req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0 poe-connector/1.0"}) with urllib.request.urlopen(req, timeout=30) as resp: Path(output_path).write_bytes(resp.read()) return True except Exception as e: print(f"Warning: auto-download failed — {e}", file=sys.stderr) return False ``` ```python url_match = re.search(r"https?://\S+", content) if url_match: url = url_match.group(0).rstrip(")") if not output_path: ext = DEFAULT_EXTENSIONS.get(media_type, ".bin") output_path = str(Path.cwd() / f"poe_generated_{media_type}{ext}") if _auto_download(url, output_path, media_type): ``` ### Technical Analysis The media-generation response is treated as trusted content. The code extracts the first HTTP or HTTPS URL from that response and passes it directly to `urllib.request.urlopen()`. No validation is applied to: - The URL hostname or port. - The resolved destination address. - Loopback, private, link-local, multicast, or reserved IP ranges. - Redirect targets. - The expected Poe or media-CDN domain. - The response content type. - The response content length. Consequently, a malicious or manipulated upstream response could cause the Skill runtime to make requests to internal services such as loopback interfaces, private network hosts, or cloud metadata endpoints. Because `urllib` follows redirects by default, checking only the original URL would not be sufficient unless every redirect destination is also validated. The call to `resp.read()` reads the entire respo ...[truncated 2289 chars]- Remediation
View remediation
