T09 · Insecure Skill Coding Practices
- Location
scripts/get_content.py:53- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
tuple[str, int | None]: """ 请求公众号链接,返回 (html, status_code)。 status_code 为 None 表示非 HTTP 错误(如连接失败)。 """ req = Request( url, headers={ "User-Agent": user_agent, "Accept": "text/html,application/xhtml+xml", "Accept-Language": "zh-CN,zh;q=0.9", }, method="GET", ) resp = urlopen(req, timeout=TIMEOUT, context=_SSL_CTX) html = resp.read().decode(resp.headers.get_content_charset() or "utf-8") return html, resp.status if hasattr(resp, "status") else 200 ``` The unvalidated value originates from the command-line argument: ```python parser.add_argument( "--url", required=True, help="公众号文章链接,如 https://mp.weixin.qq.com/s/xxx", ) ``` ### Technical Analysis The documentation describes the input as a WeChat article URL under `https://mp.weixin.qq.com/s/`, but the implementation does not enforce this restriction. The supplied URL is passed directly to `urllib.request.urlopen`. There is no validation of: - The URL scheme - The normalized hostname - The expected `/s/` path - Embedded credentials - The destination port - The resolved destination IP address - Redirect destinations Because `urlopen` follows HTTP redirects, validating only an initial URL in future changes would also be insufficient unless every redirect target is checked. An attacker can cause the process to send requests to localhost, private network addresses, link-local services, or cloud metadata endpoints. The script only prints a response when it contains an element matching `#page-content`, which limits direct disclosure for some targets. However, internal HTML applications containing that identifier can ...[truncated 1348 chars]- Remediation
View remediation
