T09 · Insecure Skill Coding Practices
- Location
- scripts/tuya_api.py:89
- Finding
- API Key Can Be Transmitted to an Arbitrary REST Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/tuya_api.py:89-105, 121-136` **Vulnerability Type**: Unrestricted authenticated endpoint override **Risk Level**: High ### Vulnerable Code ```python if api_key is None: api_key = os.environ.get("TUYA_API_KEY") if base_url is None: base_url = os.environ.get("TUYA_BASE_URL") if not api_key: raise ValueError( "Missing API key. Set environment variable TUYA_API_KEY, " "or pass api_key argument." ) if not base_url: base_url = _resolve_base_url(api_key) self.api_key = api_key self.base_url = base_url.rstrip("/") self.timeout = timeout self.session = requests.Session() self.session.headers.update({ "Authorization": f"Bearer {api_key}", }) ``` ```python def _get(self, path: str, params: dict = None): """Send GET request and return the ``result`` field directly.""" url = f"{self.base_url}{path}" resp = self.session.get(url, params=params, timeout=self.timeout) resp.raise_for_status() data = resp.json() if not data.get("success"): raise TuyaAPIError(data.get("code"), data.get("msg")) return data.get("result") def _post(self, path: str, data: dict = None): """Send POST request and return the ``result`` field directly.""" url = f"{self.base_url}{path}" resp = self.session.post(url, json=data, timeout=self.timeout) ``` ### Technical Analysis The client accepts `TUYA_BASE_URL` from the environment without validating its scheme, hostname, port, or relationship to Tuya. The API key is installed as a session-wide bearer authorization header, so every request made through that session transmits the credential to the selected endpoint. Although sending an API key to an official Tuya endpoint is necessary for the declared functionality, allowing an unrestricted destination exceeds minimum privilege. A compromised launcher, environment configuration, generated wrapper script, or local process capable of changing the environment ...[truncated 1250 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Allow only the documented Tuya HTTPS hosts by default. 2. Parse the URL using `urllib.parse.urlparse` and require: - Scheme exactly `https` - No embedded username or password - An approved hostname - An approved port, normally 443 3. Reject IP literals, malformed hosts, plaintext HTTP, and deceptive suffixes such as `trusted.example.attacker.test`. 4. Disable cross-origin redirects or strip `Authorization` whenever a redirect changes the host. 5. If custom endpoints are needed for development, require an explicit unsafe-development option and a separate non-production credential. 6. Do not place the authorization header on a reusable session until endpoint validation succeeds. 7. Document the exact authorized destination list in the data-egress statement. ]]>
