T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/caocao_mcp.py:11
- Finding
- API Key Stored in Plaintext as a URL Query Parameter<![CDATA[ ## Vulnerability Details **File Location**: `scripts/caocao_mcp.py`, lines 11 and 20–29 **Vulnerability Type**: Plaintext credential storage and credential exposure through URL query parameters **Risk Level**: Medium ### Vulnerable Code ```python BASE_TEMPLATE = 'https://mcp.caocaokeji.cn/mcp/api?key={api_key}' def save_config(path: Path, data: dict) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + '\n', encoding='utf-8') def configure(api_key: str, config_path: Path, server_name: str) -> None: data = load_config(config_path) data.setdefault('mcpServers', {})[server_name] = { 'baseUrl': BASE_TEMPLATE.format(api_key=api_key), 'description': '曹操出行 MCP', } save_config(config_path, data) ``` ### Technical Analysis The `configure` command interpolates the user's API key directly into an endpoint URL and persists that URL in `config/mcporter.json`. The configuration file is written as ordinary plaintext, and the implementation does not explicitly enforce owner-only permissions. Embedding credentials in a URL also increases their exposure surface. Full URLs can be captured by application diagnostics, exception reports, HTTP infrastructure, proxy logs, or configuration backups. HTTPS protects the request while it is in transit, but it does not prevent credential disclosure through endpoint logging or local plaintext storage. The outbound transmission itself is consistent with the declared CaoCao ride-hailing functionality. The application legitimately sends location coordinates, place names, estimate identifiers, order numbers, and cancellation reasons to `https://mcp.caocaokeji.cn`. The security issue is specifically the credential transport and storage mechanism, not the existence of the network communication. ### Attack Path 1. A user runs the documented configuration command with a valid CaoCao API key. 2. The Skill writes the key int ...[truncated 1311 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Do not place the API key in the endpoint URL.** - Use a fixed endpoint such as `https://mcp.caocaokeji.cn/mcp/api`. - Send the credential through an authorization header, for example: ```http Authorization: Bearer <API_KEY> ``` - If the service only accepts query-string credentials, request support for header-based authentication and ensure all infrastructure redacts the `key` parameter. 2. **Avoid persistent plaintext storage where possible.** - Store the key in an operating-system credential manager or dedicated secret store. - Alternatively, read it from a protected environment variable at runtime. - Keep only non-secret endpoint and server metadata in `mcporter.json`. 3. **Enforce restrictive permissions if file storage is unavoidable.** - Create the configuration file with owner-only permissions, such as mode `0600`. - Ensure the parent directory is not writable or readable by unrelated users. - Validate existing file permissions before loading credentials. 4. **Prevent secondary disclosure.** - Redact query parameters and authorization headers from logs, exceptions, telemetry, and diagnostic output. - Do not include the complete credential-bearing URL in error messages. - Exclude secret-bearing configuration files from source control and routine support bundles. 5. **Limit credential authority and lifetime.** - Use narrowly scoped keys restricted to only the necessary CaoCao operations. - Support key expiration, revocation, and rotation. - Rotate any keys that may already have been stored in logs, backups, or broadly readable configuration files. ]]>
