T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/ari.py:54
- Finding
- API Key Disclosure Through Unrestricted Custom API Endpoints and Plaintext HTTP<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ari.py:54-71`, with credential transmission sinks at `scripts/ari.py:300-320`, `scripts/ari.py:337-350`, and `scripts/ari.py:1444-1460` **Vulnerability Type**: Arbitrary credential destination and plaintext sensitive-data transmission **Risk Level**: Medium ### Vulnerable Code ```python def base_url(): """API 基址。ARI_BASE_URL 覆盖必须同时显式设置 ARI_ALLOW_CUSTOM_BASE=1 才生效: 所有请求(含带 Bearer Key 的)都发往这里,若单凭一个环境变量就能改指向, 会话里被注入的一条 shell 命令就足以把 Key 重定向到第三方主机。双变量门槛 让「指向哪」与「我确认这是自己的环境」成为两个独立动作。 """ override = (os.environ.get("ARI_BASE_URL") or "").strip().rstrip("/") if not override or override == PROD_BASE: return PROD_BASE if (os.environ.get("ARI_ALLOW_CUSTOM_BASE") or "").strip() != "1": emit(error_obj( "ARI_CUSTOM_BASE_BLOCKED", 0, "ARI_BASE_URL 指向非官方地址:%s,已拒绝发送请求" % override, "若这是你自己的开发/自建环境,请同时设置 ARI_ALLOW_CUSTOM_BASE=1 后重试;" "若你并未主动设置过 ARI_BASE_URL,请勿继续,先清除该环境变量。")) raise SystemExit(2) return override ``` The returned custom URL is subsequently used with the API key: ```python def request_json(method, path, payload=None, params=None): query = { "method": method, "path": path, "params": {k: v for k, v in (params or {}).items() if v not in (None, "")}, "payload": payload, } url = base_url() + path if query["params"]: url += "?" + urllib.parse.urlencode(query["params"], doseq=True) data = None if payload is None else json.dumps(payload).encode("utf-8") headers = { "Authorization": "Bearer " + require_key(), "Accept": "application/json", "User-Agent": user_agent(), } if data is not None: headers["Content-Type"] = "application/json" try: req = urllib.request.Request(url, data=data, headers=headers, method=method) with urllib.request.urlopen(req, timeout=TIMEOUT_SEC) as resp: ``` The ...[truncated 4238 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Require HTTPS for authenticated remote endpoints** - Parse the configured URL with `urllib.parse.urlparse`. - Reject custom endpoints whose scheme is not `https`. - Reject malformed URLs and URLs containing embedded user information. 2. **Provide a narrowly scoped local-development exception** - If plaintext HTTP is genuinely necessary, permit it only for loopback destinations such as `127.0.0.1`, `::1`, or `localhost`. - Protect that behavior behind a separate, explicitly named development flag such as `ARI_ALLOW_INSECURE_LOCAL_HTTP=1`. - Do not permit plaintext HTTP for private-network or arbitrary remote hosts. 3. **Separate production and development credentials** - Refuse to send `ari_live_*` credentials to custom endpoints. - Require a distinct development-key prefix or a separate credential variable for non-production servers. - Display a clear warning identifying the destination before using a custom endpoint. 4. **Consider destination allowlisting** - Use the official ARI hostname by default. - If self-hosted deployments are supported, allow users to configure trusted hosts explicitly rather than accepting any URL. 5. **Preserve TLS verification** - Continue using the standard verified TLS context. - Do not introduce certificate-verification bypasses for custom endpoints. 6. **Add security regression tests** - Verify rejection of `http://example.com`. - Verify rejection of malformed and credential-bearing URLs. - Verify acceptance of the official HTTPS endpoint. - If required, verify that an explicitly enabled loopback-only HTTP endpoint is accepted while other HTTP hosts remain blocked. ]]>
