Back to skill

Security audit

ifly-voiceclone-tts

Security checks for vulnerabilities and agentic risk

Overview

This skill does perform iFlytek voice cloning, but it handles voice recordings and API credentials over insecure network paths and lacks clear privacy and consent warnings.

Review before installing. Use only voices you have explicit permission to clone, avoid sensitive recordings or private synthesis text, and assume training audio, metadata, API credentials, and text are sent to iFlytek. The current implementation should be fixed to use authenticated HTTPS for training/auth and normal TLS certificate validation for synthesis before use on untrusted networks or with valuable accounts.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/voiceclone.py:49
Finding
Plaintext HTTP Transmission of Credentials, Access Tokens, and Biometric Voice Data<![CDATA[ ## Vulnerability Details **File Location**: `scripts/voiceclone.py`, lines 49–50, 239–247, 269–286, and 348–400 **Vulnerability Type**: Plaintext transmission of sensitive information **Risk Level**: High ### Vulnerable Code ```python TRAIN_BASE_URL = "http://opentrain.xfyousheng.com/voice_train" AUTH_TOKEN_URL = "http://avatar-hci.xfyousheng.com/aiauth/v1/token" ``` The authentication request is sent to the plaintext HTTP endpoint: ```python req = urllib.request.Request( AUTH_TOKEN_URL, data=body_json.encode("utf-8"), headers={ "Authorization": sign, "Content-Type": "application/json", }, ) with urllib.request.urlopen(req, timeout=30) as resp: result = json.loads(resp.read().decode("utf-8")) ``` Subsequent training requests include an access token and application identifier: ```python def _headers(self, sign: str) -> dict: return { "X-Sign": sign, "X-Token": self.token, "X-AppId": self.app_id, "X-Time": str(self._ts), "Content-Type": "application/json", } def _post(self, path: str, body: dict) -> dict: """POST JSON to training API.""" self._ensure_token() sign = self._sign_body(body) headers = self._headers(sign) data = json.dumps(body).encode("utf-8") req = urllib.request.Request( TRAIN_BASE_URL + path, data=data, headers=headers, ) with urllib.request.urlopen(req, timeout=60) as resp: return json.loads(resp.read().decode("utf-8")) ``` Local biometric voice recordings are also loaded and transmitted to the plaintext training endpoint: ```python with open(audio_path, "rb") as f: audio_data = f.read() ``` ```python headers = { "X-Sign": sign, "X-Token": self.token, "X-AppId": self.app_id, "X-Time": str(ts), "Content-Type": f"multipart/form-data; boundary={boundary}", } req = urllib.request.Request( TRAIN_BASE_URL + "/task/submitWithAudio", data=body_bytes, hea ...[truncated 2584 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace both plaintext endpoints with provider-supported HTTPS endpoints: ```python TRAIN_BASE_URL = "https://opentrain.xfyousheng.com/voice_train" AUTH_TOKEN_URL = "https://avatar-hci.xfyousheng.com/aiauth/v1/token" ``` 2. Confirm that the provider officially supports TLS on these endpoints before deployment. Do not silently fall back to HTTP if HTTPS fails. 3. Reject redirects from HTTPS to HTTP. Validate the final URL scheme and expected hostname for every request. 4. Retain Python's default certificate-chain and hostname validation. Do not install permissive SSL contexts. 5. If the provider does not offer authenticated HTTPS, do not transmit credentials or biometric recordings directly. Use a trusted, TLS-protected gateway under the operator's control or discontinue the integration. 6. Minimize token lifetime and scope where supported, and ensure server-side timestamp and nonce validation prevents replay. 7. Clearly notify users before uploading voice recordings, identify the destination service, and document the service's biometric-data retention and deletion controls. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/voiceclone.py:79
Finding
TLS Certificate and Hostname Verification Disabled for Voice Synthesis<![CDATA[ ## Vulnerability Details **File Location**: `scripts/voiceclone.py`, lines 79–84 **Vulnerability Type**: Improper TLS certificate validation **Risk Level**: High ### Vulnerable Code ```python raw = socket.create_connection((host, port), timeout=30) if parsed.scheme == "wss": ctx = ssl.create_default_context() ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE self._sock = ctx.wrap_socket(raw, server_hostname=host) else: self._sock = raw ``` The affected connection carries an authenticated URL and Base64-encoded synthesis text: ```python auth_url = build_ws_auth_url(TTS_WS_URL, self.api_key, self.api_secret) ``` ```python "text": base64.b64encode(text.encode("utf-8")).decode("utf-8"), ``` ```python request = self._build_request(self.text) ws.send(json.dumps(request)) ``` ### Technical Analysis The WebSocket URL uses `wss://`, but the client explicitly disables certificate-chain verification and hostname checking: - `ctx.verify_mode = ssl.CERT_NONE` accepts certificates that are self-signed, expired, issued by an untrusted authority, or otherwise invalid. - `ctx.check_hostname = False` permits a valid certificate for an unrelated hostname. These settings remove the server-authentication property of TLS. Encryption alone is insufficient when the client cannot verify which server controls the other end of the connection. The API authorization value is placed in the WebSocket URL query, and the user-provided synthesis text is sent after Base64 encoding. Base64 is only a transport encoding and provides no confidentiality against an endpoint or a successful man-in-the-middle. ### Attack Path 1. A victim invokes the `synth` command on a network an attacker can observe or influence. 2. The attacker intercepts the connection intended for `cn-huabei-1.xf-yun.com`. 3. The attacker presents an arbitrary TLS certificate. 4. Because certificate and hostname verification are disabled, the client accepts the attacker's endpoint ...[truncated 1005 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the insecure SSL overrides and use Python's secure defaults: ```python if parsed.scheme == "wss": ctx = ssl.create_default_context() self._sock = ctx.wrap_socket(raw, server_hostname=host) else: self._sock = raw ``` 2. Require `wss://` for synthesis and fail closed for any other scheme. 3. Restrict connections to the documented synthesis hostname or an explicit allowlist before opening the socket. 4. Preserve Server Name Indication through `server_hostname=host` and allow the default SSL context to verify both the certificate chain and hostname. 5. Do not catch certificate failures and retry with verification disabled. Report a clear error and terminate the operation. 6. Consider using a maintained WebSocket implementation with correct RFC 6455 handshake validation, TLS handling, frame limits, and timeout behavior. 7. Avoid logging or exposing the signed WebSocket URL because its query string contains temporary authorization material. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The custom WebSocket client disables both certificate validation and hostname verification for WSS connections by setting check_hostname=False and verify_mode=ssl.CERT_NONE. This makes the supposedly TLS-protected synthesis channel vulnerable to man-in-the-middle interception or modification, exposing API credentials, synthesized content, and server responses.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill clearly requires access to environment variables, local files, and outbound network connections, but the manifest does not declare any tool scope or permissions. That creates a least-privilege and transparency problem: users or hosting platforms cannot easily constrain what the skill is allowed to access, increasing the risk of unintended secret exposure or unauthorized file/network use.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
This skill enables voice cloning and uploads voice samples to a third-party service, but the documentation does not warn users about consent, impersonation, biometric privacy, or cross-border/third-party data handling risks. In this context, omission is dangerous because users may clone another person's voice or transmit sensitive biometric data without informed authorization, creating privacy, fraud, and compliance exposure.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The training workflow sends user-provided audio, task metadata, and identifiers to external iFlytek endpoints, which is privacy-relevant because voice samples are sensitive biometric data. Although the code performs the upload as part of its function, there is no explicit warning in the user-facing help or comments near the upload commands that local audio will be transmitted to third-party services for training.

Natural-Language Policy Violations

Low
Confidence
98% confidence
Finding
A substantial troubleshooting section is presented only in Chinese, despite the rest of the document being primarily in English and without indicating that the user can choose their preferred language. This creates a language/locale policy issue because the skill effectively forces one language for important operational guidance without user opt-in.

Natural-Language Policy Violations

Low
Confidence
79% confidence
Finding
The task creation logic defaults the training language to "cn", and the CLI examples and defaults are centered on Chinese unless the user overrides them. This can be interpreted as forcing a locale-specific behavior by default rather than prompting for or clearly requesting the user's language preference.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The synthesis path transmits user-supplied text and the voice resource identifier to an external WebSocket API. The script logs progress, but it does not explicitly disclose in the help text or nearby comments that synthesis input leaves the local machine and is processed by a remote provider.

Static analysis

No suspicious patterns detected.