T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/ai_hive_mcp.py:17
- Finding
- Authentication Credentials Can Be Exfiltrated Through an Unrestricted MCP Endpoint Override<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai_hive_mcp.py`, lines 17–75 **Vulnerability Type**: Unvalidated credential destination / sensitive information disclosure **Risk Level**: High ### Vulnerable Code ```python MCP_URL = os.environ.get("AI_HIVE_MCP_URL", "https://ai-hive.iclip.cn/api/mcp") ORIGIN = "https://ai-hive.iclip.cn" PROTECTED_RESOURCE = f"{ORIGIN}/.well-known/oauth-protected-resource/api/mcp" AUTHORIZATION_SERVER = f"{ORIGIN}/.well-known/oauth-authorization-server" READ_ONLY_TOOLS = {"ai_hive_list_models", "ai_hive_get_task"} def fetch_json(url: str) -> dict: request = urllib.request.Request(url, headers={"accept": "application/json"}) with urllib.request.urlopen(request, timeout=20) as response: return json.loads(response.read().decode("utf-8")) def parse_payload(raw: bytes, content_type: str) -> dict: text = raw.decode("utf-8", errors="replace").strip() if "text/event-stream" in content_type or text.startswith("event:") or text.startswith("data:"): for line in text.splitlines(): if line.startswith("data:"): candidate = line[5:].strip() if candidate and candidate != "[DONE]": return json.loads(candidate) raise RuntimeError("MCP returned SSE without a parseable data event.") if not text: return {} return json.loads(text) def auth_headers() -> dict[str, str]: key = os.environ.get("AI_HIVE_API_KEY", "").strip() token = os.environ.get("AI_HIVE_ACCESS_TOKEN", "").strip() if token: return {"authorization": f"Bearer {token}"} if key: return {"x-ai-hive-api-key": key} raise SystemExit( "Missing credentials. OAuth users should authenticate through their MCP client; " "this script requires AI_HIVE_API_KEY for tool calls, or doctor can be run without credentials." ) def post(payload: dict, session_id: str | None = None) -> tuple[dict, str | None]: he ...[truncated 2799 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Remove the endpoint override when it is not required.** Use a fixed endpoint: ```python MCP_URL = "https://ai-hive.iclip.cn/api/mcp" ``` 2. **If endpoint configurability is required, enforce an exact allowlist before obtaining or attaching credentials:** ```python from urllib.parse import urlsplit EXPECTED_SCHEME = "https" EXPECTED_HOST = "ai-hive.iclip.cn" EXPECTED_PORT = 443 EXPECTED_PATH = "/api/mcp" def validate_mcp_url(raw_url: str) -> str: parsed = urlsplit(raw_url) if parsed.scheme != EXPECTED_SCHEME: raise SystemExit("The MCP endpoint must use HTTPS.") if parsed.hostname != EXPECTED_HOST: raise SystemExit("The MCP endpoint host is not authorized.") if parsed.port not in (None, EXPECTED_PORT): raise SystemExit("The MCP endpoint port is not authorized.") if parsed.path != EXPECTED_PATH or parsed.query or parsed.fragment: raise SystemExit("The MCP endpoint path is not authorized.") if parsed.username or parsed.password: raise SystemExit("User information is not permitted in the MCP URL.") return raw_url ``` 3. **Validate the destination before calling `auth_headers()`.** Sensitive headers should only be constructed after the endpoint has passed validation. 4. **Disable cross-origin redirects for authenticated requests.** Reject redirects or explicitly verify every redirect target before resending a request. Never forward `Authorization` or `x-ai-hive-api-key` headers to a different origin. 5. **Separate public metadata requests from authenticated requests.** Keep OAuth metadata retrieval credential-free and use a dedicated authenticated transport for the fixed MCP endpoint. 6. **Fail closed.** If URL parsing or validation is ambiguous, terminate without sending the request. 7. **Add automated security tests** confirming rejection of: - HTTP endpoints. - Alternate domains and subdomains. - Nonstandard ports. - User-information UR ...[truncated 315 chars]
