T09 · Insecure Skill Coding Practices
Warning
- Location
- market_intel.py:309
- Finding
- Custom News Endpoints Permit Plaintext Transmission of API Credentials and User Queries<![CDATA[ ## Vulnerability Details **File Location**: `market_intel.py`, lines 309-317 **Vulnerability Type**: Sensitive information transmitted over an untrusted or unencrypted network channel **Risk Level**: Medium ### Vulnerable Code ```python def fetch_custom_news(source, query, max_results=5): base = os.getenv(f"{source.upper()}_BASE_URL", "") api_key = os.getenv(f"{source.upper()}_API_KEY", "") if not base: raise RuntimeError(f"缺少 {source.upper()}_BASE_URL") payload = {"query": query, "max_results": max_results} headers = {"Content-Type": "application/json"} if api_key: headers["Authorization"] = f"Bearer {api_key}" data = http_json(base, method="POST", headers=headers, payload=payload) ``` ### Technical Analysis The custom Bocha and MiniMax integrations obtain their destination URL directly from the `BOCHA_BASE_URL` or `MINIMAX_BASE_URL` environment variable. The URL is passed to the generic HTTP client without validating its scheme or destination host. If the configured URL uses `http://`, the script transmits the following data without transport encryption: - The provider API key in the `Authorization: Bearer` header. - The user-supplied search query in the JSON request body. - The requested result count and related request metadata. An attacker able to observe or manipulate the network connection could read the credential and query or alter the server response. Because arbitrary configured hosts are accepted, a malicious or incorrectly configured endpoint can also directly collect this information. The behavior exceeds minimum privilege because the declared news-search functionality requires network access but does not require permitting plaintext credential transmission to unrestricted hosts. ### Attack Path 1. An attacker influences the `BOCHA_BASE_URL` or `MINIMAX_BASE_URL` configuration, or an operator mistakenly configures an `http://` endpoint. 2. A corresponding API key is present in `BOCHA_ ...[truncated 1129 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Parse each configured endpoint with `urllib.parse.urlparse()` and reject every scheme other than `https`. 2. Maintain an explicit allowlist of approved hostnames for each provider rather than accepting arbitrary destinations. 3. Reject URLs containing embedded credentials, unexpected ports, fragments, or malformed hostnames. 4. Disable automatic redirects for authenticated requests, or validate every redirect target and remove `Authorization` before any cross-origin redirect. 5. Send provider credentials only to the exact approved HTTPS origin. 6. Fail closed with a clear configuration error when endpoint validation fails. 7. Use narrowly scoped, revocable API keys and rotate any credential that may previously have been sent through plaintext HTTP. 8. Document that custom endpoint configuration is security-sensitive and must not be derived from untrusted user input. Example validation approach: ```python from urllib.parse import urlparse ALLOWED_CUSTOM_HOSTS = { "bocha": {"api.bocha.example"}, "minimax": {"api.minimax.example"}, } def validate_custom_endpoint(source, base): parsed = urlparse(base) if parsed.scheme != "https": raise RuntimeError("Custom news endpoints must use HTTPS") if parsed.hostname not in ALLOWED_CUSTOM_HOSTS.get(source, set()): raise RuntimeError("Custom news endpoint host is not approved") if parsed.username or parsed.password or parsed.fragment: raise RuntimeError("Invalid custom news endpoint") return base ``` ]]>
