T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/fetch_episodes.py:38- Finding
Unrestricted RSS and enclosure URL fetching permits server-side request forgery
- Content
View full analysis
Vulnerability Details
File Location:
scripts/fetch_episodes.py:38-77
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: Highpython def parse_rss(url: str) -> list[dict]: resp = requests.get(url, timeout=30, headers={"User-Agent": UA}) resp.raise_for_status() root = ElementTree.fromstring(resp.content) episodes = [] for item in root.iter("item"): title = item.findtext("title", "").strip() pub_date = item.findtext("pubDate", "").strip() desc = item.findtext("description", "").strip() enc = item.find("enclosure") audio_url = enc.get("url") if enc is not None else None link = item.findtext("link", "").strip() episodes.append({ "title": title, "pub_date": pub_date, "description": desc, "audio_url": audio_url, "link": link, }) return episodes def existing_episodes(archive_dir: Path) -> set[str]: slugs = set() if not archive_dir.exists(): return slugs for d in archive_dir.iterdir(): if d.is_dir() and (d / "episode.json").exists(): slugs.add(d.name) return slugs def download_direct(url: str, dest: Path) -> bool: """Try direct HTTP download.""" try: resp = requests.get(url, timeout=120, stream=True, headers={"User-Agent": UA}) resp.raise_for_status() ct = resp.headers.get("content-type", "") if "audio" in ct or "octet-stream" in ct or url.endswith(".mp3"): with open(dest, "wb") as f: for chunk in resp.iter_content(chunk_size=8192): f.write(chunk) return True except Exception: pass return FalseTechnical Analysis
The Skill accepts an arbitrary RSS URL through
--rssorHN_PODCAST_RSSand sends an HTTP request to it with ...[truncated 1926 chars]- Remediation
View remediation
Remediation Suggestions
- Permit only
httpsURLs unless insecure HTTP support is explicitly required. - Resolve destination hostnames before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6.
- Disable automatic redirects or validate every redirect destination before following it.
- Re-resolve and revalidate the hostname at connection time to reduce DNS rebinding exposure.
- Consider requiring enclosure hosts to match the RSS feed host or an explicit user-approved allowlist.
- Apply the same validation policy to the RSS request, direct audio download, and
yt-dlpfallback. - Run download processing in a sandbox with restricted network access where practical.
- Enforce maximum RSS and audio response sizes to limit resource exhaustion from hostile endpoints.
- Permit only
