Back to skill

Security audit

FlowUs息流平替迁移:AI-HIVE多模型工作流

Security checks for vulnerabilities and agentic risk

Overview

The skill is a disclosed AI-HIVE migration helper, but it includes broad remote tool-calling and an unsafe endpoint override that could expose credentials or submitted data.

Install only if you are comfortable connecting this skill to AI-HIVE and using AI-HIVE credentials. Prefer OAuth through the MCP client, keep API keys in a secret store, do not set AI_HIVE_MCP_URL unless you fully trust the endpoint, use only safe test documents, and review each tool call and paid action before approving it.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ai_hive_mcp.py:20
Finding
Unrestricted MCP Endpoint Can Expose Credentials and Submitted Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/ai_hive_mcp.py`, lines 20–68 **Vulnerability Type**: Unvalidated network destination for authenticated requests **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 complete login in their MCP client; " "tool calls from this script require AI_HIVE_API_KEY, or run doctor only." ) def post(payload: dict, session_id: str | None = None) -> tuple[dict, str | None]: headers = { "content-type": "a ...[truncated 2988 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Remove arbitrary endpoint overrides unless operationally required.** Use the fixed documented MCP endpoint: ```python MCP_URL = "https://ai-hive.iclip.cn/api/mcp" ``` 2. **If configurability is required, validate the destination before constructing authenticated requests.** Require: - The `https` scheme. - The exact approved hostname `ai-hive.iclip.cn`. - The expected `/api/mcp` path. - No embedded username or password. - No unexpected port. - No IP-literal or look-alike hostname. 3. **Enforce an explicit origin allowlist**, for example: ```python from urllib.parse import urlparse ALLOWED_HOSTS = {"ai-hive.iclip.cn"} def validate_mcp_url(url: str) -> str: parsed = urlparse(url) if parsed.scheme != "https": raise SystemExit("The MCP endpoint must use HTTPS.") if parsed.hostname not in ALLOWED_HOSTS: raise SystemExit("The MCP endpoint host is not approved.") if parsed.username or parsed.password: raise SystemExit("Credentials must not be embedded in the MCP URL.") if parsed.port not in (None, 443): raise SystemExit("Unexpected MCP endpoint port.") if parsed.path != "/api/mcp": raise SystemExit("Unexpected MCP endpoint path.") return url ``` 4. **Disable automatic cross-origin redirects for authenticated requests**, or implement a redirect handler that rejects any redirect whose origin differs from the validated endpoint. Never forward API keys or bearer tokens to a different origin. 5. **Separate credential attachment from generic request handling.** Only add authorization headers after the destination has passed validation. 6. **Use least-privilege, short-lived credentials where supported.** Apply narrow scopes, account-level spending limits, expiration, and prompt revocation procedures. 7. **Add automated security tests** confirming that authenticated requests reject: - ...[truncated 173 chars]
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (5)

Tainted flow: 'request' from os.environ.get (line 67, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Content
method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=60) as response:
            result = parse_payload(response.read(), response.headers.get("content-type", ""))
            return result, response.headers.get("mcp-session-id") or session_id
    except urllib.error.HTTPError as error:
Confidence
83% confidence
Finding
The script sends credentials from environment variables to a network endpoint whose base URL is overridable via AI_HIVE_MCP_URL. If an attacker can influence that environment variable or package execution context, they can redirect requests and exfiltrate the API key or bearer token to an attacker-controlled server.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill instructs users to run local scripts, export API keys in environment variables, read/write local files, and connect to a remote MCP endpoint, yet it declares no permissions. This creates a transparency and governance gap: hosts or reviewers may underestimate the skill’s ability to access secrets, local data, and the network, increasing the risk of unintended data exposure or unsafe execution.

Description-Behavior Mismatch

Medium
Confidence
85% confidence
Finding
The implementation is a generic MCP diagnostic and invocation client, while the manifest describes a much narrower FlowUs migration/model-selection assistant. This scope mismatch increases attack surface by granting broader remote capabilities than users would reasonably expect from the skill description.

Context-Inappropriate Capability

High
Confidence
92% confidence
Finding
The call subcommand permits invocation of arbitrary MCP tools, with only a weak billing confirmation gate for non-read-only tools. For a skill advertised for a specific migration-assessment workflow, this enables unexpected remote actions or data access through any tool exposed by the MCP server.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The skill enables implicit invocation globally via `allow_implicit_invocation: true`, but the YAML provides no trigger constraints, exclusion conditions, or narrow activation rules. That can cause the skill to activate based on broad user phrasing and unexpectedly route user requests to the external AI-HIVE MCP endpoint, increasing the chance of unintended tool use and data exposure.

Static analysis

No suspicious patterns detected.