T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/generate_brief.py:18
- Finding
- Unrestricted URL Fetching Enables Server-Side Request Forgery and Local Resource Access<![CDATA[ ## Vulnerability Details **File Location**: `scripts/generate_brief.py`, lines 18–23, 312, 326, 334, and 342 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unrestricted URI scheme handling **Risk Level**: High ### Vulnerable Code ```python def fetch_text(url: str, timeout: int) -> str: req = urllib.request.Request(url, headers={"User-Agent": "openclaw-hn-rss-brief/1.0"}) with urllib.request.urlopen(req, timeout=timeout) as r: charset = r.headers.get_content_charset() or "utf-8" return r.read().decode(charset, errors="replace") ``` The initial OPML source is retrieved without destination validation: ```python if args.opml_url: opml_text = fetch_text(args.opml_url, timeout=args.timeout) else: with open(args.opml_file, 'r', encoding='utf-8') as f: opml_text = f.read() feed_urls = parse_opml(opml_text)[: args.max_feeds] ``` Every URL extracted from the OPML document is subsequently fetched: ```python def work(url: str) -> Tuple[str, List[Entry], Optional[str]]: try: text = fetch_text(url, timeout=args.timeout) es = parse_feed(url, text) return url, es, None except Exception as e: return url, [], str(e) ``` ### Technical Analysis The Skill legitimately requires outbound network access to retrieve an OPML subscription list and its RSS or Atom feeds. However, the implementation grants substantially broader network access than this functionality requires. Both the user-supplied `--opml-url` and every `xmlUrl` extracted from an OPML document are passed directly to `urllib.request.urlopen`. The implementation does not: - Restrict requests to HTTP or HTTPS. - Require encrypted HTTPS transport. - Reject URLs containing embedded credentials. - Block loopback, private, link-local, multicast, reserved, or cloud metadata IP addresses. - Revalidate hostnames after DNS resolution. - Validate redirect destinations. - Restrict feed retrieval to trusted domains. - Exp ...[truncated 2336 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only `https` URLs for remote OPML and feed retrieval. Explicitly reject `file`, `ftp`, `data`, and all other schemes. 2. Reject URLs containing usernames, passwords, malformed hosts, or ambiguous numeric IP representations. 3. Resolve the hostname before connecting and reject every resolved address belonging to loopback, private, link-local, multicast, unspecified, reserved, or documentation ranges. 4. Explicitly block cloud metadata destinations, including link-local metadata addresses and provider-specific metadata hostnames. 5. Disable automatic redirects or validate every redirect target using the same scheme, hostname, DNS, and IP controls. 6. Protect against DNS rebinding by ensuring the validated address is the address used for the connection, or by using a hardened outbound proxy. 7. Where practical, enforce a domain allowlist for the initial OPML source and expected feed domains. 8. Run the Skill in a sandbox with no access to sensitive local files, cloud metadata services, or internal administrative networks. 9. Record rejected destinations and validation failures without exposing sensitive response content. 10. Apply the same validation function to both `--opml-url` and every URL extracted from OPML. ]]>
