T09 · Insecure Skill Coding Practices
- Location
scripts/monitor.py:113- Finding
Unrestricted Feed URLs Allow SSRF and Local Resource Access
- Content
View full analysis
List[str]: """Try to discover RSS/Atom feeds from a regular webpage URL.""" url = (url or "").strip() if not url: return [] if url.endswith((".rss", ".xml", ".atom")) or url.endswith("/feed"): return [url] request = Request( url, headers={ "User-Agent": "topic-monitor/1.5 (+feed-discovery)", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", }, ) try: with urlopen(request, timeout=timeout) as response: content_type = response.headers.get("Content-Type", "") final_url = response.geturl() body = response.read(250_000) except Exception: return [] ``` Feed URLs are subsequently fetched without destination validation: ```python for feed_url in all_feeds: headers = feed_cache_headers(state, topic_id, feed_url) if verbose: print(f" 📰 Fetching feed: {feed_url}") parsed = feedparser.parse(feed_url, request_headers=headers) update_feed_cache(state, topic_id, feed_url, parsed) ``` Directly supplied and discovered URLs are stored without validation: ```python feeds = split_csv(args.feeds) if args.discover_feeds: discovered = [] for candidate in split_csv(args.discover_feeds): discovered.extend(discover_feed_urls(candidate)) feeds = list(dict.fromkeys(feeds + discovered)) ``` OPML URLs are also accepted without validation: ```python for outline in outlines: xml_url = outline.attrib.get("xmlUrl") or outline.attrib.get("xmlurl") title = outline.attrib.get("title") ...[truncated 3077 chars]- Remediation
View remediation
