T09 · Insecure Skill Coding Practices
- Location
scripts/yufluent_api.py:21- Finding
Bearer Token and Business Data May Be Transmitted over Cleartext HTTP
- Content
View full analysis
str: base = (base_url or "").strip().rstrip("/") if not base: base = "http://localhost:8080/v1" if base.endswith("/v1"): return base return f"{base}/v1" ``` ```python def _auth_headers(api_key: str) -> dict[str, str]: return { "Authorization": f"Bearer {api_key}", "Accept": "application/json", } ``` ```python def _post_json( url: str, *, api_key: str, body: dict[str, Any] | None = None, timeout: float, ) -> requests.Response: kwargs: dict[str, Any] = { "headers": _json_headers(api_key) if body is not None else _auth_headers(api_key), "timeout": timeout, } if body is not None: kwargs["json"] = body return requests.post(url, **kwargs) ``` ```python root = base_url or os.getenv("TOKENAPI_BASE_URL", "") url = skill_run_url(root, skill_id) try: resp = _post_json(url, api_key=key, body=payload, timeout=timeout) ``` ### Technical Analysis The client accepts `TOKENAPI_BASE_URL` without validating its scheme or destination. It then sends `TOKENAPI_KEY` as a bearer token in the `Authorization` header and submits the user-provided SEO payload to that endpoint. The default endpoint uses HTTP on localhost, which is ordinarily limited to local traffic. However, the implementation also permits a non-loopback endpoint such as `http://remote-host/v1`. In that configuration, the bearer token and payload are transmitted without TLS confidentiality or server authentication. The transmitted payload can include product names, seed keywords, competitor keywords, target markets, ...[truncated 1862 chars]- Remediation
View remediation
str: normalized = normalize_api_root(base_url) parsed = urlparse(normalized) if parsed.scheme not in {"http", "https"}: raise ValueError("API URL must use HTTP or HTTPS") host = parsed.hostname or "" loopback = host == "localhost" if not loopback: try: loopback = ipaddress.ip_address(host).is_loopback except ValueError: loopback = False if parsed.scheme != "https" and not loopback: raise ValueError("HTTPS is required for non-loopback API endpoints") return normalized ``` ]]>
