T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/ari.py:55
- Finding
- Bearer API Key Can Be Sent to a Custom Plaintext HTTP Endpoint<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ari.py:55-71`, with the authenticated network sink at `scripts/ari.py:300-320` **Vulnerability Type**: Insufficient transport security validation for sensitive credentials **Risk Level**: Medium ### Vulnerable Code ```python def base_url(): 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 self-hosted environment, explicitly set ARI_ALLOW_CUSTOM_BASE=1.")) raise SystemExit(2) return override ``` The returned custom URL is subsequently used by the authenticated request function: ```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: ``` Equivalent authenticated behavior also occurs in `request_sse()` and `request_download()`. ### Technical Analysis The custom endpoint protection requires both `ARI_BASE_URL` and `ARI_ALLOW_CUSTOM_BASE=1`, which helps prevent accidental redir ...[truncated 2775 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse custom endpoints before accepting them: ```python parsed = urllib.parse.urlparse(override) ``` 2. Require HTTPS for all non-local authenticated endpoints: ```python if parsed.scheme != "https": raise SystemExit("Custom ARI endpoints must use HTTPS") ``` 3. If plaintext HTTP is required for local development, permit it only when all of the following are true: - The hostname is a loopback address such as `127.0.0.1`, `::1`, or `localhost`. - A separate, clearly named flag such as `ARI_ALLOW_INSECURE_LOCAL_HTTP=1` is present. - The documentation explicitly warns that production API keys must not be used in this mode. 4. Reject malformed or ambiguous endpoint forms, including: - Unsupported schemes such as `file`, `ftp`, or scheme-relative URLs. - URLs containing embedded user information. - URLs containing query strings or fragments. - Empty or invalid hostnames. 5. Apply the same validated endpoint object consistently to JSON, SSE, public, and download request functions. 6. Add automated tests confirming that: - The official HTTPS endpoint is accepted. - Custom HTTPS endpoints require explicit opt-in. - External HTTP endpoints are rejected even with the current custom-base opt-in. - Local HTTP endpoints are rejected unless a separate development-only flag is enabled. - Unsupported and malformed URL schemes cannot receive an authorization header. 7. Update `references/reference.md` and user documentation to state that authenticated custom endpoints must use TLS. ]]>
