T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/generate.py:129
- Finding
- Gemini API Key Forwarded to an Unvalidated Remote URL## Vulnerability Details **File Location**: `scripts/generate.py`, lines 129-135 **Vulnerability Type**: Credential disclosure through an untrusted download destination **Risk Level**: Medium **Vulnerable Code**: ```python video_uri = outputs[0].get('video', {}).get('uri') if video_uri: print(f"Downloading video from: {video_uri[:60]}...") video_response = requests.get(video_uri, headers={"x-goog-api-key": api_key}, timeout=60) with open(output_path, 'wb') as f: f.write(video_response.content) print(f"✅ Video saved to: {output_path}") ``` ### Technical Analysis The video download URI comes from the remote API response and is used directly as a request destination. The script does not validate the URI scheme or hostname before attaching the `GEMINI_API_KEY` in the `x-goog-api-key` header. Consequently, a malicious, compromised, or otherwise unexpected upstream response could provide an attacker-controlled URI. The subsequent request would disclose the API key to that destination. The `requests` library also follows redirects by default, and the code does not validate redirect destinations or disable redirects. Sending credentials to arbitrary response-provided destinations exceeds the minimum privileges required by the declared functionality. Video retrieval should be restricted to documented Google-owned service endpoints or performed through an official SDK that does not expose the API key to an arbitrary download host. The downloaded response is also written without checking the HTTP status, content type, or response size. While the file is not executed by this script, this could allow an invalid or unexpectedly large response to be written to the caller-selected output path. ### Attack Path 1. A user invokes the Skill with video generation enabled. 2. The script submits the generated image and video prompt to the declared Gemini endpoint. 3. The script polls for completion and reads ...[truncated 897 chars]
- Remediation
- ## Remediation Suggestions 1. Parse the returned URI with `urllib.parse.urlparse`. 2. Require the `https` scheme and an explicit allowlist of documented Google download hostnames. 3. Reject embedded credentials, unexpected ports, malformed hostnames, and hostnames that merely use an allowed suffix deceptively. 4. Disable automatic redirects with `allow_redirects=False`, or validate every redirect destination before following it. 5. Prefer an official Google SDK download method or a scoped, short-lived signed URL that does not require forwarding the API key. 6. Call `raise_for_status()` before writing the response. 7. Validate the response content type and enforce a maximum download size. 8. Stream the response into a temporary file and atomically replace the requested output only after successful validation. 9. Restrict the Gemini API key by API, application, quota, and billing controls wherever supported. Example validation pattern: ```python from urllib.parse import urlparse allowed_hosts = { "generativelanguage.googleapis.com", # Add only Google hosts explicitly documented for video downloads. } parsed = urlparse(video_uri) if parsed.scheme != "https" or parsed.hostname not in allowed_hosts: raise ValueError("Unapproved video download URI") video_response = requests.get( video_uri, headers={"x-goog-api-key": api_key}, timeout=60, allow_redirects=False, stream=True, ) video_response.raise_for_status() ```
