T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/ari.py:61
- Finding
- Bearer API Key Can Be Transmitted to an Arbitrary Non-TLS Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ari.py:61-71`, `scripts/ari.py:304-320`, `scripts/ari.py:336-350`, `scripts/ari.py:1457-1460` **Vulnerability Type**: Insufficient validation of an authenticated network destination **Risk Level**: Medium ### Vulnerable Code ```python def base_url(): """API base URL. A custom ARI_BASE_URL requires ARI_ALLOW_CUSTOM_BASE=1.""" 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 points to a non-official address: %s; request refused" % override, "For a development or self-hosted environment, also set " "ARI_ALLOW_CUSTOM_BASE=1.")) raise SystemExit(2) return override ``` The authenticated JSON request path subsequently attaches 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 same destination selection is used for SSE requests and authenticated downloads: ```python headers = { "Authorization": "Bearer " + r ...[truncated 2748 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse custom base URLs with `urllib.parse.urlsplit()` and reject malformed values. 2. Require `https` for every non-loopback custom endpoint. 3. If plaintext HTTP is needed for local development, permit it only for explicit loopback addresses such as `127.0.0.1`, `::1`, or `localhost`. 4. Reject URLs containing embedded usernames or passwords. 5. Consider an allowlist for approved self-hosted domains. 6. Do not forward the `Authorization` header across redirects to a different origin. Prefer disabling redirects for authenticated calls or validating every redirect target. 7. Replace or supplement the environment-only opt-in with an explicit CLI trust operation that records the approved origin and displays a clear warning. 8. Compare the normalized origin before attaching credentials, and fail closed if the origin differs from the trusted destination. 9. Add tests covering HTTP destinations, malformed URLs, cross-origin redirects, embedded credentials, and environment-variable injection. ]]>
