T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/vivago_client.py:65
- Finding
- Configurable API Host Can Receive the Vivago Bearer Token<![CDATA[ ## Vulnerability Details **File Location**: `scripts/vivago_client.py:65-83`, `scripts/vivago_client.py:89-97`, `scripts/vivago_client.py:355-368` **Vulnerability Type**: Authenticated request redirection through unrestricted configuration **Risk Level**: Medium ### Complete Code Snippet ```python def __init__( self, token: str, ports_config_path: Optional[str] = None ): """ Initialize Vivago client. Args: token: Vivago API Bearer token ports_config_path: Path to api_ports.json (optional) """ self.token = token self.headers = { "Authorization": f"Bearer {token}", "X-accept-language": "en", } # Load ports configuration self.ports_config = self._load_ports_config(ports_config_path) self.base_url = self.ports_config.get("base_url", "https://vivago.ai/api/gw") ``` ```python def _load_ports_config(self, config_path: Optional[str] = None) -> Dict: try: if config_path: with open(config_path, 'r', encoding='utf-8') as f: return json.load(f) else: return load_ports_config() ``` ```python try: url = f"{self.base_url}{endpoint}" headers_post = {**self.headers, "Content-Type": "application/json"} response = requests.post( url, json=data, headers=headers_post, timeout=1800 ) ``` ### Technical Analysis The API client accepts an arbitrary configuration file through `ports_config_path`. The file can define `base_url`, which is used directly to construct API request URLs. The client does not verify that the configured URL: - Uses HTTPS. - Belongs to `vivago.ai` or an explicitly trusted subdomain. - Has no embedded credentials or unexpected port. - Resolves to a non-local, trusted destination. Every generated request includes the Vivago bearer token through the `Authorization` header. Therefore, control over the configuration path or contents is sufficient to redirect au ...[truncated 1345 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Enforce an explicit destination allowlist before sending authenticated requests: ```python from urllib.parse import urlparse ALLOWED_API_HOSTS = {"vivago.ai"} def validate_api_base_url(url: str) -> str: parsed = urlparse(url) if parsed.scheme != "https": raise ValueError("The API base URL must use HTTPS") if parsed.hostname not in ALLOWED_API_HOSTS: raise ValueError("Untrusted API host") if parsed.username or parsed.password: raise ValueError("Embedded URL credentials are prohibited") return url.rstrip("/") ``` 2. Validate endpoint fields and require them to be relative paths beginning with a single `/`. Reject absolute URLs, network-path references, backslashes, fragments, and traversal components. 3. Do not forward credentials to custom hosts. If custom endpoints are genuinely required, make credential forwarding a separate explicit option that defaults to disabled. 4. Prefer removing `ports_config_path` from untrusted entry points and package reviewed endpoint definitions as immutable application data. 5. Add tests confirming that HTTP URLs, unrelated domains, localhost, IP literals, and absolute endpoint URLs are rejected. 6. Rotate any Vivago token that may already have been used with an untrusted configuration. ]]>
