T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/monitor.py:262
- Finding
- Unrestricted Feed and Entry URLs Enable Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/monitor.py:71-78`, `scripts/monitor.py:87-100`, `scripts/monitor.py:246-269`, and `scripts/monitor.py:420-422` **Vulnerability Type**: Server-Side Request Forgery through unvalidated feed and article URLs **Risk Level**: High ### Vulnerable Code ```python for url in feed_urls: if verbose: print(f"[RSS] Fetching {url} …", file=sys.stderr) try: resp = requests.get(url, timeout=10, headers={"User-Agent": "AI-Launch-Monitor/1.0"}) resp.raise_for_status() feed = feedparser.parse(resp.content) ``` The resulting feed entry URLs are accepted without validation: ```python for entry in feed.entries: published = _entry_date(entry) if published and published < cutoff: continue title = entry.get("title", "") summary = entry.get("summary", entry.get("description", "")) link = entry.get("link", "") if not (title and link): continue is_launch = bool(LAUNCH_KEYWORDS.search(title + " " + summary)) entries.append({ "title": _clean(title), "link": link, "summary": _clean(summary)[:500], "published": published.isoformat() if published else None, "source": feed.feed.get("title", urlparse(url).netloc), "is_launch_signal": is_launch, }) ``` Those untrusted URLs are subsequently opened in Chromium: ```python with sync_playwright() as p: browser = p.chromium.launch(headless=True, args=["--no-sandbox"]) context = browser.new_context(viewport={"width": 1280, "height": 800}) page = context.new_page() for launch in launches: url = launch["link"] fname = hashlib.md5(url.encode()).hexdigest()[:10] + ".png" fpath = shot_dir / fname try: page.goto(url, timeout=20000, wait_until="domcontentloaded") page.wait_for_timeout(2000) page.screenshot(path=str(fpath), full_page=False) launch["screenshot"] ...[truncated 3636 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Create a single URL-validation function and apply it before every feed fetch and browser navigation. 2. Permit only `https` URLs unless an explicit, documented exception is required. 3. Reject URLs containing embedded credentials and reject non-web schemes such as `file`, `data`, `javascript`, and `ftp`. 4. Resolve the destination hostname and reject every resolved loopback, private, link-local, multicast, unspecified, and reserved IP address, for both IPv4 and IPv6. 5. Disable automatic redirects or validate every redirect target before following it. Validate the final connected destination as well as the original URL. 6. Mitigate DNS rebinding by binding validation to the actual connection destination or enforcing network-layer egress controls. 7. Consider an allowlist of approved feed domains. If arbitrary public feeds are required, clearly warn users that they expand the network trust boundary. 8. Run browser traffic in an isolated environment with no access to the host network, private subnets, cloud metadata addresses, or sensitive local services. 9. Remove `--no-sandbox`. If the deployment environment cannot run Chromium's sandbox, isolate the entire browser in a hardened, unprivileged container instead. 10. Limit the number of redirects, response size, request duration, and total pages visited to reduce denial-of-service exposure. 11. Add security tests covering loopback addresses, private IPv4 and IPv6 ranges, encoded IP representations, redirects to private hosts, and DNS rebinding scenarios. ]]>
