T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/download_wechat_video.py:95
- Finding
- Unrestricted URL Handling Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/download_wechat_video.py:95` and `scripts/download_wechat_video.py:64-77` **Vulnerability Type**: Unrestricted URL access / server-side request forgery **Risk Level**: High ### Vulnerable Code The supplied article URL is opened without validating its scheme, hostname, resolved IP address, or redirect destination: ```python result = run_browser_command("open", {"targetUrl": article_url}) ``` The video URL extracted from that page is subsequently passed directly to `curl`: ```python cmd = [ "curl", "-L", "-o", output_path, "-H", f"User-Agent: {user_agent}", "-H", f"Referer: {referer}", "-H", "Accept: video/webm,video/ogg,video/mp4,application/octet-stream", "--progress-bar", video_url ] print(f"开始下载视频到:{output_path}") result = subprocess.run(cmd) ``` ### Technical Analysis The skill documentation presents the input as a WeChat article URL, but the implementation does not enforce that boundary. Any caller-provided URL is forwarded to the OpenClaw browser. The extracted video source is also trusted without validating its origin before it is passed to `curl`. Because `curl` uses `-L`, redirects are followed without checking whether the final destination remains on an approved WeChat or Tencent host. The implementation also does not prohibit loopback, private, link-local, or other internal network addresses. Argument-array subprocess execution prevents shell metacharacter injection, but it does not prevent URL-based request forgery. An attacker-controlled page can expose a crafted video source referring to a network destination accessible from the machine running the skill. ### Attack Path 1. An attacker causes the skill to receive a URL outside the intended `mp.weixin.qq.com` scope. 2. The script passes the URL to `openclaw browser open` without validation. 3. The attacker-controlled page presents a matching video playback button. 4. After the script clicks the butt ...[truncated 951 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse the article URL with `urllib.parse.urlsplit` and require: - The `https` scheme. - No embedded username or password. - An exact approved hostname, such as `mp.weixin.qq.com`. - A valid, expected port. 2. Resolve the hostname and reject loopback, private, link-local, reserved, multicast, and unspecified addresses using Python's `ipaddress` module. 3. Validate every redirect destination rather than relying on unrestricted `curl -L` behavior. 4. Apply equivalent validation to the extracted video URL. Allow only explicitly approved HTTPS video hosts, such as the required WeChat or Tencent media domains. 5. Restrict curl protocols, for example with `--proto =https` and `--proto-redir =https`. 6. Consider performing the download through application code with explicit redirect callbacks so each redirect target can be revalidated. 7. Apply network-level egress controls to prevent the process from reaching loopback, private networks, and cloud metadata services where those destinations are unnecessary. ]]>
