T09 · Insecure Skill Coding Practices
- Location
scripts/pack_wechat.py:142- Finding
Unrestricted Server-Side Request Forgery Through Image and Cover URLs
- Content
View full analysis
Vulnerability Details
File Location:
scripts/pack_wechat.py:142-153,scripts/pack_wechat.py:173-175, andscripts/pack_wechat.py:324-327
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: HighVulnerable Code
python def _download_url(url: str, dest_dir: str) -> str: _ensure_dir(dest_dir) req = urllib.request.Request(url, headers={"User-Agent": "wechat-pack/1.0"}) with urllib.request.urlopen(req) as resp: data = resp.read() ext = _guess_ext_from_content_type(resp.headers.get("Content-Type", "")) base = _slugify(os.path.basename(urllib.parse.urlparse(url).path)) if not os.path.splitext(base)[1] and ext: base = f"{base}{ext}" filename = _unique_path(os.path.join(dest_dir, base)) with open(filename, "wb") as f: f.write(data) return filenamepython if src.startswith("http://") or src.startswith("https://"): local_path = _download_url(src, assets_dir) new_src = os.path.relpath(local_path, os.path.join(assets_dir, "..", "wechat"))python if args.cover.startswith("http://") or args.cover.startswith("https://"): cover_path = _download_url(args.cover, cover_dir)Technical Analysis
URLs embedded in source HTML or Markdown and URLs passed through the
--coverargument are retrieved directly by the host. The implementation does not apply a hostname allowlist, resolve and validate destination IP addresses, restrict access to internal address ranges, or validate redirect destinations.Consequently, an attacker who controls a source document or cover URL can cause the process to issue HTTP requests to loopback interfaces, private networks, link-local services, or cloud instance metadata endpoints. Because the response is written into the generated package, the behavior may also expose response content to the package recipient.
Attack Path
- An attacker crea ...[truncated 1061 chars]
- Remediation
View remediation
Remediation Suggestions
- Permit downloads only from explicitly trusted HTTPS hosts.
- Resolve hostnames before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6.
- Prevent DNS rebinding by connecting only to the validated resolved address while preserving TLS hostname verification.
- Disable automatic redirects or validate every redirect destination with the same URL and IP policy.
- Reject URLs containing credentials or malformed host representations.
- If arbitrary external images are required, perform retrieval through an isolated proxy with strict egress controls.
- Log rejected destinations without recording credentials or sensitive URL parameters.
