T09 · Insecure Skill Coding Practices
- Location
scripts/imou_client.py:22- Finding
Unrestricted API Base URL Can Redirect Sensitive Requests to an Arbitrary Server
- Content
View full analysis
Vulnerability Details
File Location:
scripts/imou_client.py:22-23, 40-62; related configuration flow inscripts/device_video.py:27-28and documentation inSKILL.md:43-57, 109-113
Vulnerability Type: Unvalidated sensitive-data destination
Risk Level: HighComplete Code Snippet
python def _get_base_url(): return os.environ.get("IMOU_BASE_URL", "").strip() or DEFAULT_BASE_URLpython def _request(method: str, params: dict, app_id: str, app_secret: str, base_url: str = None) -> dict: """ Send one Open API request. :param method: API method name (e.g. 'accessToken', 'bindDeviceLive'). :param params: Request params object. :param app_id: App ID. :param app_secret: App secret for sign. :param base_url: Optional base URL; uses env IMOU_BASE_URL or default if None. :return: Full response body as dict; check result.code for '0'. """ base = base_url or _get_base_url() url = f"{base.rstrip('/')}/openapi/{method}" time_sec = int(time.time()) nonce = uuid.uuid4().hex sign = _build_sign(time_sec, nonce, app_secret) body = { "system": { "ver": "1.0", "appId": app_id, "sign": sign, "time": time_sec, "nonce": nonce, }, "id": str(uuid.uuid4()), "params": params, } headers = { "Content-Type": "application/json", OPENCLAW_HEADER: OPENCLAW_HEADER_VALUE, } resp = requests.post(url, headers=headers, json=body, timeout=30) resp.raise_for_status() return resp.json()The CLI also passes the environment-controlled value directly into every request:
python APP_ID = os.environ.get("IMOU_APP_ID", "") APP_SECRET = os.environ.get("IMOU_APP_SECRET", "") BASE_URL = os.environ.get("IMOU_BASE_URL", "").strip() or "https://openapi.lechange.cn"Technical A
...[truncated 3172 chars]
- Remediation
View remediation
Remediation Suggestions
- Parse the configured URL with
urllib.parse.urlparse. - Require the
httpsscheme and reject HTTP, protocol-relative URLs, fragments, query strings, and embedded username/password components. - Allowlist the documented Imou API hosts:
openapi.lechange.cnopenapi-sg.easy4ip.comopenapi-fk.easy4ip.comopenapi-or.easy4ip.com
- Validate ports, permitting only the expected HTTPS port where an explicit port is present.
- Reject unexpected base paths rather than concatenating
/openapi/{method}onto an arbitrary path. - If private or test endpoints are operationally necessary, require a separate explicit unsafe-development option and display a prominent warning before transmitting credentials.
- Keep TLS certificate verification enabled and consider using a dedicated
requests.Sessionwith a narrowly scoped adapter or destination policy. - Update
SKILL.mdto state that the plaintextappSecretis used locally to derive a signature rather than directly sent, while clearly listing all other transmitted sensitive fields. - Add automated tests covering HTTP URLs, unknown hosts, embedded credentials, malformed ports, and unexpected paths.
- Parse the configured URL with
