T09 · Insecure Skill Coding Practices
- Location
scripts/topmediai_tts_api.py:20- Finding
Unvalidated API Base URL Can Redirect Credentials and TTS Content
- Content
View full analysis
Dict[str, str]: key = api_key or DEFAULT_KEY if not key: raise RuntimeError( "TOPMEDIAI_API_KEY not configured. Edit: {} and set TOPMEDIAI_API_KEY=YOUR_KEY.".format(_ENV_PATH) ) return {"x-api-key": key, "Content-Type": "application/json"} ``` ```python def text_to_speech(text: str, speaker: str, emotion: Optional[str] = None, api_key: Optional[str] = None) -> Dict[str, Any]: url = f"{BASE_URL}/v1/text2speech" headers = _headers(api_key) payload: Dict[str, Any] = { "text": text, "speaker": speaker, } if emotion: payload["emotion"] = emotion _debug_request("POST", url, headers=headers, payload=payload) try: r = requests.post(url, json=payload, headers=headers, timeout=120) r.raise_for_status() return r.json() except Exception as e: _raise_as_runtime_error(e, "POST", url) ``` The same base URL and credential-bearing headers are also used by the account-information and voice-list requests. ### Technical Analysis `TOPMEDIAI_BASE_URL` is accepted directly from the process environment or project `.env` file without validating its scheme, hostname, port, or embedded credentials. The application subsequently attaches the TopMediai API key as an `x-api-key` header to requests sent to that destination. Consequently, anyone able to alter the process environment or `.env` configuration can redirect requests to an attacker-controlled endpoint. For TTS operations, both the API key and the user-supplied tex ...[truncated 1712 chars]- Remediation
View remediation
str: parsed = urlparse(value) if parsed.scheme != "https": raise RuntimeError("TOPMEDIAI_BASE_URL must use HTTPS") if parsed.hostname not in ALLOWED_API_HOSTS: raise RuntimeError("TOPMEDIAI_BASE_URL host is not approved") if parsed.username or parsed.password or parsed.fragment: raise RuntimeError("TOPMEDIAI_BASE_URL contains unsupported components") if parsed.port not in (None, 443): raise RuntimeError("TOPMEDIAI_BASE_URL uses an unapproved port") return value.rstrip("/") BASE_URL = validate_base_url( os.environ.get("TOPMEDIAI_BASE_URL", "https://api.topmediai.com") ) ``` ]]>
