T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/utils.py:13
- Finding
- Environment-Controlled API Base Can Exfiltrate Credentials and Sensitive User Content<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils.py:13-15, 160-181`; `scripts/voice_clone.py:80-95, 134-149`; `scripts/sync_tts.py:171-173` **Vulnerability Type**: Unrestricted destination for authenticated sensitive-data requests **Risk Level**: High ### Vulnerable Code ```python # scripts/utils.py:13-15 MINIMAX_VOICE_API_KEY = os.getenv("MINIMAX_VOICE_API_KEY") MINIMAX_API_BASE = os.getenv("MINIMAX_API_BASE", "https://api.minimaxi.com/v1") MINIMAX_API_BASE_BACKUP = "https://api-bj.minimaxi.com/v1" ``` ```python # scripts/utils.py:160-181 base_url = MINIMAX_API_BASE_BACKUP if use_backup else MINIMAX_API_BASE url = f"{base_url}/{endpoint.lstrip('/')}" if files: headers = { "Authorization": f"Bearer {MINIMAX_VOICE_API_KEY}", "Accept-Encoding": "gzip, deflate", } else: headers = get_headers() response = requests.request( method=method, url=url, headers=headers, json=data if not files else None, data=data if files else None, files=files, params=params, timeout=timeout, ) response.raise_for_status() return response.json() ``` ```python # scripts/voice_clone.py:80-95 url = f"{MINIMAX_API_BASE}/files/upload" headers = {"Authorization": f"Bearer {MINIMAX_VOICE_API_KEY}"} with open(file_path, "rb") as f: files = {"file": (os.path.basename(file_path), f)} data = {"purpose": "voice_clone"} response = requests.post( url, headers=headers, files=files, data=data, timeout=timeout, ) ``` ```python # scripts/voice_clone.py:134-149 url = f"{MINIMAX_API_BASE}/files/upload" headers = {"Authorization": f"Bearer {MINIMAX_VOICE_API_KEY}"} with open(file_path, "rb") as f: files = {"file": (os.path.basename(file_path), f)} data = {"purpose": "prompt_audio"} response = requests.post( url, headers=headers, files=files, data=data, timeout=timeout, ) ``` ```python # scripts/sync_tts. ...[truncated 2770 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove arbitrary runtime override support unless it is strictly required. 2. Use a fixed official endpoint for production requests: ```python MINIMAX_API_BASE = "https://api.minimaxi.com/v1" ``` 3. If endpoint customization is necessary, parse and validate it with `urllib.parse.urlsplit`: - Require `https` - Require an explicit allowlisted MiniMax hostname - Reject embedded usernames or passwords - Reject fragments and unexpected ports - Normalize the hostname before comparison 4. Maintain a narrow allowlist, for example: ```python ALLOWED_API_HOSTS = { "api.minimaxi.com", "api-bj.minimaxi.com", } ``` 5. Disable automatic redirects for requests carrying credentials, or verify every redirect target before following it. 6. Do not automatically forward production credentials to custom endpoints. Require a separate credential explicitly configured for a custom endpoint. 7. Before uploading voice samples, clearly disclose the resolved destination and require confirmation when it differs from the official service. 8. Add tests that verify rejection of HTTP URLs, deceptive subdomains, embedded credentials, alternate ports, and attacker-controlled hosts. ]]>
