T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/senseaudio_tts.py:29
- Finding
- Unrestricted Endpoint Configuration and Response URL Handling## Vulnerability Details **File Location**: `scripts/senseaudio_tts.py`, lines 29 and 58–111 **Vulnerability Type**: Arbitrary credential forwarding, server-side request forgery, and unbounded response retrieval **Risk Level**: Medium ### Vulnerable Code ```python parser.add_argument("--url", default=DEFAULT_URL, help="SenseAudio API URL.") ``` ```python def build_request(args: argparse.Namespace, text: str) -> urllib.request.Request: api_key = args.api_key or os.environ.get("SENSEAUDIO_API_KEY") if not api_key: raise SystemExit("Missing API key. Set SENSEAUDIO_API_KEY or pass --api-key.") payload = { "model": args.model, "text": text, "voice_setting": {"voice_id": args.voice_id}, } data = json.dumps(payload).encode("utf-8") headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", } return urllib.request.Request(args.url, data=data, headers=headers, method="POST") ``` ```python def maybe_download_url(url: str) -> bytes: with urllib.request.urlopen(url) as resp: return resp.read() ``` ```python url_candidates = [ payload.get("audio_url"), payload.get("url"), payload.get("data", {}).get("audio_url"), payload.get("data", {}).get("url"), payload.get("result", {}).get("audio_url"), payload.get("result", {}).get("url"), ] for item in url_candidates: if isinstance(item, str) and item: return maybe_download_url(item) ``` ### Technical Analysis The command-line `--url` option accepts an arbitrary destination and passes it directly to `urllib.request.Request`. The request always includes the SenseAudio bearer credential and submitted TTS text. There is no enforcement of HTTPS, no trusted-host allowlist, and no separation between credentials intended for SenseAudio and credentials sent to a custom endpoint. Consequently, anyone who can influence the invocation may redirect the API key and potentially sensitive ...[truncated 2577 chars]
- Remediation
- ## Remediation Suggestions 1. Remove the `--url` option unless custom API providers are a required feature. If custom providers must be supported, require explicit opt-in and do not automatically send the SenseAudio credential to them. 2. Enforce HTTPS for the API endpoint and maintain an allowlist of approved API hostnames, such as the documented SenseAudio host. 3. Bind credentials to their intended origin. Refuse to attach the SenseAudio bearer token when the request host differs from the approved SenseAudio API host. 4. Validate every response-provided media URL before opening it: - Permit only `https` URLs. - Allowlist trusted media hosts. - Resolve the hostname and reject loopback, private, link-local, multicast, reserved, and unspecified addresses. - Revalidate every redirect destination and resolved address. - Reject local-file and other non-HTTP(S) schemes. 5. Configure explicit connection and read timeouts for both the API call and secondary download. 6. Stream responses in bounded chunks instead of calling `read()` without a limit. Enforce a maximum API response size and maximum audio size before writing data. 7. Verify the downloaded content type and, where supported, expected content length before accepting it as audio. 8. Avoid disclosing raw provider error bodies if they can contain sensitive data; return sanitized diagnostic information instead. 9. Add tests covering arbitrary endpoint rejection, credential origin binding, redirects to private addresses, non-HTTPS URLs, local URL schemes, oversized responses, and slow-response timeouts.
