T09 · Insecure Skill Coding Practices
- Location
scripts/publish_wechat.py:151- Finding
Unrestricted URL Fetching Enables Server-Side Request Forgery
- Content
View full analysis
Article: resp = requests.get(url, timeout=30) resp.raise_for_status() ``` ```python def upload_image_from_url(self, token: str, image_url: str) -> str: img = requests.get(image_url, timeout=self.timeout) img.raise_for_status() ``` ```python if is_url(input_value): article = extract_from_url(input_value) ``` ### Technical Analysis The script accepts an arbitrary HTTP or HTTPS URL and retrieves it using the network privileges of the host running the Skill. It does not validate the destination hostname, resolved IP address, port, or redirect target. The article extraction logic also obtains the first image URL from fetched HTML. During publication, that image can be retrieved by `upload_image_from_url`. Consequently, an attacker can trigger requests either directly through the input argument or indirectly through attacker-controlled article content. No controls prevent requests to: - Loopback addresses such as `127.0.0.1` or `::1` - Private network ranges - Link-local addresses - Cloud instance metadata services - Internal administrative services - Destinations reached after an HTTP redirect The image request is particularly useful for blind SSRF because the attacker can control the image URL embedded in an otherwise legitimate-looking article. ### Attack Path 1. An attacker provides an article URL such as `http://127.0.0.1:PORT/internal` or a URL resolving to a private address. 2. The Skill recognizes it as a URL because it begins with `http://` or `https://`. 3. `extract_from_url` issues the request from the Agent host without validating the destination. 4. The response is processed a ...[truncated 981 chars]- Remediation
View remediation
