T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/ai_hive_mcp.py:19
- Finding
- User-Controlled MCP Endpoint Can Receive AI-HIVE Credentials<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai_hive_mcp.py`, lines 19 and 47–70 **Vulnerability Type**: Credential disclosure through an unrestricted network endpoint override **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 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( "缺少凭据。OAuth 用户请在 MCP 客户端中完成登录;本脚本调用工具时需通过环境变量提供 " "AI_HIVE_API_KEY,或仅运行 doctor。" ) def post(payload: dict, session_id: str | None = None) -> tuple[dict, str | None]: headers = { "content-type": "application/json", "accept": "application/json, text/event-stream", **auth_headers(), } if session_id: headers["mcp-session-id"] = session_id request = urllib.request.Request( MCP_URL, data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), headers=headers, method="POST", ) ``` ### Technical Analysis The MCP destination is read from the externally controlled `AI_HIVE_MCP_URL` environment variable. No validation requires the destination to use HTTPS or to belong to the declared AI-HIVE origin. The `post()` function independently obtains an API key or bearer access token from the environment and attaches it to every request sent to `MCP_URL`. Consequently, changing only `AI_HIVE_MCP_URL` is sufficient to redirect the credential and MCP request payloads to an arbitrary server. The OAuth metadata U ...[truncated 2245 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove the `AI_HIVE_MCP_URL` override if endpoint customization is not required: ```python MCP_URL = "https://ai-hive.iclip.cn/api/mcp" ``` 2. If customization is required, parse and validate the URL before constructing authenticated requests: - Require the `https` scheme. - Require an exact allowlisted hostname. - Require the expected port and path. - Reject embedded usernames and passwords. - Reject malformed, relative, or non-network URLs. 3. Bind credentials to an explicit destination: ```python from urllib.parse import urlparse ALLOWED_MCP_ORIGINS = {("https", "ai-hive.iclip.cn", 443)} def validate_mcp_url(url: str) -> str: parsed = urlparse(url) port = parsed.port or 443 if ( (parsed.scheme, parsed.hostname, port) not in ALLOWED_MCP_ORIGINS or parsed.path != "/api/mcp" or parsed.username or parsed.password or parsed.query or parsed.fragment ): raise SystemExit("Refusing to send credentials to an unapproved MCP endpoint.") return url ``` 4. Disable automatic redirects for authenticated requests or revalidate every redirect destination before forwarding authentication headers. Credentials must never be forwarded across origins. 5. Separate endpoint selection from credential attachment. If a non-production endpoint is intentionally supported, require a separate credential variable and explicit confirmation rather than reusing production credentials. 6. Add automated tests confirming rejection of: - Plain HTTP endpoints. - Lookalike and subdomain-confusion hosts. - Unexpected ports or paths. - URLs containing user information. - Cross-origin redirects. 7. Document that environment variables affecting authenticated destinations are security-sensitive and should not be accepted from untrusted project files, launchers, or CI input. ]]>
