T09 · Insecure Skill Coding Practices
- Location
sdk/core/client.py:166- Finding
Arbitrary URL Fetch Enables SSRF and Exfiltration Through Remote Media Upload
- Content
View full analysis
Vulnerability Details
File Location:
sdk/core/client.py:166-186,sdk/core/client.py:207-226; duplicate URL-fetch behavior inscripts/kaipai_ai.py:269-290
Vulnerability Type: Server-Side Request Forgery followed by remote data upload
Risk Level: HighVulnerable Code
python def _download_to_temp(self, url: str) -> Tuple[str, int]: """Download URL to temp file. Returns (path, size).""" max_b = url_download_max_bytes() conn_t = url_download_connect_timeout() read_t = url_download_read_timeout() resp = requests.get( url, stream=True, timeout=(conn_t, read_t), headers={"User-Agent": USER_AGENT}, ) resp.raise_for_status() fd, path = tempfile.mkstemp(prefix="kaipai_in_", suffix=".bin") total = 0 try: with os.fdopen(fd, "wb") as f: for chunk in resp.iter_content(chunk_size=65536): if chunk: total += len(chunk) if total > max_b: raise RuntimeError(f"File too large (max {max_b} bytes)") f.write(chunk) except Exception: os.unlink(path) raise return path, totalpython if source.startswith(("http://", "https://")): _progress_log(f"Downloading from URL: {source[:64]}...") tmp_path, size = self._download_to_temp(source) try: _progress_log(f"Downloaded {size} bytes, uploading to OSS...") url_data = self.api.upload_file(tmp_path) finally: os.unlink(tmp_path)Technical Analysis
The client accepts any URL beginning with
http://orhttps://. It does not validate the resolved IP address, reject loopback or private address ranges, block cloud metadata services, or restrict the destination to approved media providers.The default behavior of
requests.get()also follows redirects. Cons ...[truncated 1647 chars]- Remediation
View remediation
Remediation Suggestions
- Parse URLs using
urllib.parse.urlsplit()and permit only HTTPS unless HTTP is explicitly necessary. - Resolve all destination hostnames before connecting and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for both IPv4 and IPv6.
- Explicitly block cloud metadata addresses and hostnames, including link-local metadata endpoints.
- Disable redirects or validate the destination hostname and resolved IP after every redirect.
- Defend against DNS rebinding by connecting only to the validated address and ensuring the HTTP host and TLS certificate match the approved hostname.
- Prefer an allowlist of trusted media/CDN domains where practical.
- Validate the response MIME type and file signature before upload.
- Apply one centralized URL-validation implementation to
run-task,resolve-input, cover-image downloads, and all duplicate download paths. - Avoid uploading fetched content until it has passed media validation.
- Parse URLs using
