T09 · Insecure Skill Coding Practices
Error
- Location
- lib/generate-image.py:115
- Finding
- KIE API Key Disclosure Through Unvalidated Image Download URL in Image Generator<![CDATA[ ## Vulnerability Details **File Location**: `lib/generate-image.py:115-160` **Vulnerability Type**: Credential disclosure through an untrusted network destination **Risk Level**: High ### Vulnerable Code ```python result_json_str = data.get("resultJson", "{}") try: result_data = json.loads(result_json_str) images = result_data.get("resultUrls", result_data.get("images", [])) if images: output_dir = Path(__file__).parent.parent / "images" output_dir.mkdir(exist_ok=True) downloaded_paths = [] for i, img_url in enumerate(images, 1): timestamp = time.strftime("%Y-%m-%d-%H-%M-%S") output_path = output_dir / f"{timestamp}-{i}.png" if download_image(img_url, str(output_path)): downloaded_paths.append(str(output_path)) ``` ```python def download_image(url, output_path): """Download image from URL with auth headers""" try: # Try with authorization header first headers = { "Authorization": f"Bearer {API_KEY}", "User-Agent": "Mozilla/5.0" } req = urllib.request.Request(url, headers=headers) with urllib.request.urlopen(req, timeout=30) as response: with open(output_path, 'wb') as f: f.write(response.read()) return True ``` ### Technical Analysis The download URL is obtained from the remotely supplied `resultJson.resultUrls` or `resultJson.images` field. The code does not validate the URL scheme, hostname, port, or relationship to `api.kie.ai` before attaching the user's `KIE_API_KEY` as a bearer token. Consequently, a task response containing an attacker-controlled HTTPS URL causes the Skill to send the API credential directly to the attacker's server. Sending this credential is not necessary for ordinary downloads from public or pre-signed CDN URLs and exceeds the minimum privileges needed for image retrieval. This behavior also contradicts the source ...[truncated 1245 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not attach `KIE_API_KEY` to generated-asset URLs. Attempt downloads without credentials by default. 2. If authenticated downloads are genuinely required, validate the URL before adding the header: - Require `https`. - Use an exact hostname allowlist controlled by the developer. - Reject embedded credentials, unexpected ports, and malformed hostnames. - Do not use suffix-only checks vulnerable to names such as `trusted.example.attacker.test`. 3. Disable redirects or validate every redirect destination before forwarding authorization headers. 4. Keep API authentication requests limited to the fixed `api.kie.ai` origin. 5. Add download limits for response size, content type, and timeout to reduce resource-exhaustion risks. 6. Update the security manifest to document all actual network destinations and authentication behavior. 7. Rotate any KIE API key previously used with affected versions if untrusted task responses may have been processed. A safer baseline is: ```python def download_image(url, output_path): parsed = urllib.parse.urlparse(url) if parsed.scheme != "https": raise ValueError("Only HTTPS image URLs are permitted") req = urllib.request.Request( url, headers={"User-Agent": "kie-ai-skill/1.0"} ) with urllib.request.urlopen(req, timeout=30) as response: with open(output_path, "wb") as f: f.write(response.read()) ``` ]]>
