T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/ghost.py:127
- Finding
- Arbitrary Remote Image Retrieval Enables SSRF and Internal Data Relay<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ghost.py`, lines 127–163 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unrestricted data relay **Risk Level**: High ### Vulnerable Code ```python def download_image(url): """下载远程图片到临时文件""" try: print(f"⏳ 正在从远程下载图片: {url}") response = requests.get(url, timeout=10) response.raise_for_status() # 提取扩展名 import urllib.parse path = urllib.parse.urlparse(url).path ext = os.path.splitext(path)[1] or '.jpg' if ext.lower() not in ['.jpg', '.jpeg', '.png', '.gif', '.webp']: ext = '.jpg' temp_path = f"temp_download_{int(datetime.now().timestamp())}{ext}" with open(temp_path, 'wb') as f: f.write(response.content) return temp_path except Exception as e: print(f"❌ 下载远程图片失败: {e}") return None def create_post(config, title, content, status='draft', tags=None, excerpt=None, feature_image=None): """创建新文章 (自动检测并转换 Markdown)""" # 如果 feature_image 是远程 URL,尝试先下载并上传到 Ghost (确保稳定性) if feature_image and feature_image.startswith('http') and 'fu-ye.com' not in feature_image: print(f"📸 检测到外部图片 URL,正在尝试本地化上传...") local_path = download_image(feature_image) if local_path: ghost_image_url = upload_image(config, local_path) if ghost_image_url: feature_image = ghost_image_url # 清理临时文件 try: os.remove(local_path) except: pass ``` ### Technical Analysis The `feature_image` value is accepted as a remote URL and passed directly to `requests.get`. The implementation does not validate the URL scheme, destination hostname, resolved IP address, redirect destinations, response content type, or response size. The condition checking whether the text `fu-ye.com` occurs in the URL is not a security boundary. It does not establish that a destination is ...[truncated 1763 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only explicitly supported URL schemes, preferably `https`. 2. Parse URLs with `urllib.parse.urlsplit` and reject malformed URLs, embedded credentials, and unexpected ports. 3. Resolve the hostname before connecting and reject loopback, private, link-local, reserved, multicast, and unspecified IPv4 and IPv6 addresses. 4. Disable redirects or validate every redirect destination using the same hostname and resolved-address policy. 5. Stream responses with a strict maximum byte count rather than loading the entire body into memory. 6. Verify that the response has an approved image media type and validate the actual file signature. 7. Consider restricting downloads to an explicit hostname allowlist. 8. Require explicit user confirmation before retrieving a remote feature image. 9. Do not automatically upload remotely retrieved data unless the retrieval and destination have both been validated. ]]>
