T09 · Insecure Skill Coding Practices
- Location
ask_leonidas.py:43- Finding
Unrestricted API Base Can Disclose Bearer Credentials and User Data
- Content
View full analysis
Dict[str, Any]: req = urllib.request.Request( url, data=json.dumps(payload).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": f"Bearer {api_key}", "X-Client": "openclaw", }, method="POST", ) with urllib.request.urlopen(req, timeout=timeout_seconds) as resp: return json.loads(resp.read().decode("utf-8")) ``` #### `ask_leonidas.py:99-112` ```python api_base = get_env("ASK_LEONIDAS_API_BASE", "").rstrip("/") api_key = get_env("ASK_LEONIDAS_API_KEY", "") timeout = int(get_env("ASK_LEONIDAS_TIMEOUT_SECONDS", str(DEFAULT_TIMEOUT))) if not api_base: print(json.dumps({"error": "ASK_LEONIDAS_API_BASE is not set."}, ensure_ascii=False)) return 1 if not api_key: print(json.dumps({"error": "ASK_LEONIDAS_API_KEY is not set."}, ensure_ascii=False)) return 1 url = api_base + "/api/v1/openclaw/generate" payload = build_payload(args) ``` #### `healthcheck.py:14-32` ```python api_base = os.environ.get("ASK_LEONIDAS_API_BASE", "").rstrip("/") api_key = os.environ.get("ASK_LEONIDAS_API_KEY", "") timeout = int(os.environ.get("ASK_LEONIDAS_TIMEOUT_SECONDS", str(DEFAULT_TIMEOUT))) if not api_base: print(json.dumps({"error": "ASK_LEONIDAS_API_BASE is not set."}, ensure_ascii=False)) return 1 if not api_key: print(json.dumps({"error": "ASK_LEONIDAS_API_KEY is not set."}, ensure_ascii=False)) return 1 req = urllib.request.Request( api_base + "/api/v1/openclaw/he ...[truncated 3691 chars]- Remediation
View remediation
str: parsed = urlparse(value) if parsed.scheme != "https": raise ValueError("ASK_LEONIDAS_API_BASE must use HTTPS.") if parsed.hostname != TRUSTED_HOST: raise ValueError("ASK_LEONIDAS_API_BASE must target askleonidas.com.") if parsed.username or parsed.password: raise ValueError("Embedded URL credentials are not allowed.") if parsed.port not in (None, 443): raise ValueError("Unexpected API port.") return "https://askleonidas.com" ``` 3. **Apply identical validation in every client** Centralize endpoint and credential handling in one shared function used by both `ask_leonidas.py` and `healthcheck.py`. This prevents the health check from becoming a less-protected credential disclosure path. 4. **Separate development endpoint support** If custom endpoints are required for local development, require an explicit development flag and use a separate non-production credential. Never transmit a live production key to a custom host. 5. **Constrain browser fallback** Open only the fixed trusted URL: ```python webbrowser.open("https://askleonidas.com/openclaw") ``` Do not derive the browser destination from a ...[truncated 618 chars]
