T09 · Insecure Skill Coding Practices
Error
- Location
- script/audio2text_cli.py:111
- Finding
- Unrestricted Service Endpoint Allows API Key and Audio Disclosure## Vulnerability Details **File Location**: `script/audio2text_cli.py`, lines 111–115 and 160–202 **Vulnerability Type**: Unvalidated network destinations and sensitive-data exposure **Risk Level**: High ### Vulnerable Code ```python parser.add_argument( "--base-url", type=str, default=DEFAULT_BASE_URL, help=f"API 基础地址,默认 {DEFAULT_BASE_URL}", ) ``` ```python base = args.base_url.rstrip("/") headers = {"Authorization": f"Bearer {api_key}"} filename = path.name audio_format = get_format_from_path(args.audio_path) # 1) 获取 OpenClaw 上传凭证 token_url = f"{base}/tos/openclaw/upload-token?{urllib.parse.urlencode({'filename': filename})}" try: status, raw = _http_get(token_url, headers, timeout=30) except urllib.error.HTTPError as e: try: raw_err = e.read() body = json.loads(raw_err.decode("utf-8")) msg = body.get("message", raw_err.decode("utf-8", errors="replace")) except Exception: msg = str(e) print(f"获取上传凭证失败: {msg}", file=sys.stderr) sys.exit(1) except Exception as e: print(f"获取上传凭证失败: {e}", file=sys.stderr) sys.exit(1) data = _parse_json_response(status, raw, "获取上传凭证失败") payload = data.get("data", {}) signed_url = payload.get("signed_url") key = payload.get("key") if not signed_url or not key: print("响应缺少 signed_url 或 key", file=sys.stderr) sys.exit(1) # 2) 上传到 TOS try: with open(path, "rb") as f: body_bytes = f.read() put_status = _http_put(signed_url, body_bytes, timeout=120) ``` ### Technical Analysis The CLI allows callers to replace the intended Tinrec API endpoint with any value through `--base-url`. It does not enforce HTTPS, verify the destination hostname, restrict ports, or otherwise ensure that the endpoint belongs to Tinrec. The program then constructs an `Authorization: Bearer` header containing the user's Tinrec API key and sends it directly to the ...[truncated 2792 chars]
- Remediation
- ## Remediation Suggestions 1. **Remove unrestricted endpoint overrides in production.** Use the fixed `https://api.tinrec.com/api` endpoint for normal operation. If endpoint replacement is needed for testing, place it behind an explicit development-only mode with prominent warnings. 2. **Validate the API destination before sending credentials.** - Require the `https` scheme. - Allowlist `api.tinrec.com`. - Reject embedded user information, fragments, unexpected ports, malformed hosts, and hostname suffix tricks. - Compare parsed hostnames rather than using substring or naive suffix checks. 3. **Validate the returned upload URL before opening the audio file.** - Require HTTPS. - Allowlist the documented Tinrec/TOS storage hostname or narrowly defined hostname set. - Reject unexpected ports, user-information components, and unapproved destinations. - Perform validation on the normalized parsed URL. 4. **Control redirects.** Reject redirects to origins outside the relevant allowlist. Ensure authorization headers are never forwarded to a different origin. 5. **Minimize credential exposure.** Prefer a permission-restricted key file or secret manager over `--api-key`, because command-line arguments may be visible through process inspection or shell history. Recommend restrictive key-file permissions, such as owner read/write only. 6. **Add explicit user disclosure.** Before upload, clearly identify the validated remote service receiving the recording, particularly when the file may contain confidential conversations. 7. **Add negative security tests.** Verify that the CLI rejects HTTP URLs, lookalike domains, embedded credentials, unapproved ports, attacker-controlled signed URLs, and redirects to untrusted origins.
