T09 · Insecure Skill Coding Practices
- Location
scripts/query_holiday.py:235- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
str: """Fetch and extract the main body text from a gov.cn notice page.""" response = requests.get( url, headers={ "User-Agent": "Mozilla/5.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", }, timeout=20, ) response.raise_for_status() response.encoding = response.apparent_encoding or response.encoding or "utf-8" html = response.text text = _extract_div_text( html, lambda attrs: "trs_editor_view" in (attrs.get("class") or "").split(), ) if not text: text = _extract_div_text(html, lambda attrs: attrs.get("id") == "UCAP-CONTENT") if not text: raise SystemExit(f"Could not extract notice body from {url}") return text ``` The command-line interface accepts the URL directly: ```python body_parser = sub.add_parser("body", help="Fetch a notice body") body_parser.add_argument("url") ``` ```python if args.command == "body": print_body(args.url) return ``` ### Technical Analysis The `body` command passes an unrestricted, caller-supplied URL into `requests.get()`. The application does not validate: - The URL scheme - The destination hostname - The resolved IP address - The destination port - Whether the address belongs to a loopback, private, link-local, or reserved network - Redirect destinations Although the function documentation describes fetching a gov.cn notice, this restriction is not enforced in code. The HTTP client follows redirects by default, so validating only the initial URL would also be insufficient ...[truncated 2021 chars]- Remediation
View remediation
