T09 · Insecure Skill Coding Practices
- Location
scripts/price_watch.py:121- Finding
Server-Side Request Forgery Through Unrestricted Product URLs
- Content
View full analysis
None: p = urlparse(url) if p.scheme not in {"http", "https"}: raise ValueError("Only http/https URLs are allowed") if not p.netloc: raise ValueError("Invalid URL") def fetch_html(url: str) -> str: validate_url(url) req = Request(url, headers={"User-Agent": UA}) with urlopen(req, timeout=TIMEOUT) as r: content_type = (r.headers.get("Content-Type") or "").lower() if "text/html" not in content_type and "application/xhtml+xml" not in content_type: raise ValueError(f"Unsupported content type: {content_type}") raw = r.read(MAX_BYTES + 1) if len(raw) > MAX_BYTES: raise ValueError("Response too large") return raw.decode("utf-8", errors="replace") ``` The direct URL is accepted and persisted through this flow: ```python def cmd_add(args: argparse.Namespace) -> int: data = load_store() result = add_watch_item(data, args.url, args.target_price, args.currency) save_store(data) print(json.dumps({"ok": True, "item": result, "store": str(STORE_PATH)})) return 0 ``` Stored URLs are subsequently fetched through this flow: ```python def check_one(item: Dict[str, Any]) -> Dict[str, Any]: checked_at = now_iso() try: title, price, debug = parse_product(item["url"]) except Exception as e: return {"id": item["id"], "ok": False, "error": str(e), "checkedAt": checked_at} ``` ### Technical Analysis The URL validation only confirms that the scheme is `http` or `https` and that a network location exists. It does not reject: - Loopback addresses such as `127.0.0.1` or `::1` - Private network ranges - Link-local addresses - Cloud instance ...[truncated 2561 chars]- Remediation
View remediation
