T09 · Insecure Skill Coding Practices
- Location
scripts/parse_chatgpt_share.py:35- Finding
Domain Allowlist Bypass Through HTTP and Unvalidated Redirects
- Content
View full analysis
None: """校验 URL 是否为合法的 ChatGPT 共享链接""" if not ALLOWED_URL_PATTERN.match(url): raise ValueError( f"不支持的 URL 格式: {url}\n" f"仅支持 ChatGPT 共享链接,格式如: https://chatgpt.com/share/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" ) def fetch_html(url: str) -> str: """用 Python 标准库下载共享页面 HTML(不依赖 curl)""" validate_url(url) req = urllib.request.Request( url, headers={ "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/125.0.0.0 Safari/537.36", }, ) try: with urllib.request.urlopen(req, timeout=60) as resp: raw = resp.read() # 尝试从 Content-Type 获取编码,默认 utf-8 charset = resp.headers.get_content_charset() or "utf-8" html = raw.decode(charset, errors="replace") ``` ### Technical Analysis The parser validates only the URL initially supplied to `fetch_html()`. Python's default `urllib.request.urlopen()` behavior follows HTTP redirects automatically, but the code does not validate each redirect target or inspect and validate `resp.geturl()` after the request completes. As a result, an initially permitted ChatGPT URL can cause the client to fetch content from a destination outside the documented allowlist if the permitted endpoint returns a redirect. The regular expression also explicitly permits both `http://` and `https://`, despite the documentation describing an HTTPS-only restriction. Permitting plaintext HTTP creates a practical int ...[truncated 1619 chars]- Remediation
View remediation
