Back to skill

Security audit

GPT-SoVITS TTS

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but its output path can be abused to run local shell commands when the skill is called with untrusted input.

Install only if you trust every caller that can set outputPath and you are comfortable sending the input text to the configured GPT-SoVITS endpoint. Treat reference voice recordings as sensitive biometric data and use only voices you have permission to clone. The ffmpeg call should be changed to execFileSync/spawnSync with argument arrays and output paths should be restricted to a dedicated directory before broad use.

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
index.js:57
Finding
OS Command Injection Through the Output Path<![CDATA[ ## Vulnerability Details **File Location**: `index.js`, lines 57–61 **Vulnerability Type**: OS command injection through unsanitized shell interpolation **Risk Level**: High ### Vulnerable Code ```js const outMp3 = outputPath.replace(/\.wav$/i, '.mp3'); execSync( `ffmpeg -y -i "${tmpWav}" -codec:a libmp3lame -b:a 128k -ar 44100 -ac 1 "${outMp3}"`, { stdio: 'ignore', timeout: 30000 } ); ``` ### Technical Analysis The caller-controlled `outputPath` value is assigned to `outMp3` and interpolated directly into a command passed to `child_process.execSync()`. Because `execSync()` invokes a shell, shell metacharacters contained in the path are interpreted as command syntax. Surrounding the interpolated path with double quotes does not prevent exploitation. An attacker can include a double quote to terminate the quoted argument, append a command using shell separators such as `;`, and comment out the remainder. The `.replace()` operation only changes a trailing `.wav` extension and does not validate or escape shell syntax. This flaw is reachable whenever an untrusted or insufficiently trusted caller can control the `outputPath` argument passed to the exported `speak()` function. ### Attack Path 1. An attacker gains control over the `outputPath` supplied by an application, automation workflow, messaging integration, or other caller of `speak()`. 2. The attacker supplies a value containing shell syntax, for example: ```text audio.mp3"; touch /tmp/pwn; # ``` 3. The value is interpolated into the shell command, producing behavior equivalent to: ```sh ffmpeg ... "audio.mp3"; touch /tmp/pwn; #" ``` 4. After the `ffmpeg` command is processed, the shell executes the injected `touch /tmp/pwn` command. 5. An attacker could replace this demonstration command with any command available to the operating-system account running the Node.js process. Successful exploitation requires the TTS API request to complete and execution to reach the ` ...[truncated 806 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Avoid invoking a shell. Replace `execSync()` with `execFileSync()` or `spawnSync()` and pass every argument separately: ```js const { execFileSync } = require('child_process'); const outMp3 = outputPath.replace(/\.wav$/i, '.mp3'); execFileSync('ffmpeg', [ '-y', '-i', tmpWav, '-codec:a', 'libmp3lame', '-b:a', '128k', '-ar', '44100', '-ac', '1', outMp3, ], { stdio: 'ignore', timeout: 30000, }); ``` Passing arguments as an array prevents the output path from being interpreted as shell syntax. Apply additional defense-in-depth controls: 1. Require `outputPath` to be a non-empty string with an approved extension. 2. Resolve the path with `path.resolve()` and restrict it to a designated output directory. 3. Reject paths containing null bytes or paths that escape the designated directory. 4. Run the process under a dedicated, least-privileged operating-system account. 5. Place temporary-file cleanup in a `finally` block so failed conversions do not leave files behind. 6. Add security tests using paths containing quotes, semicolons, command substitutions, spaces, and traversal sequences. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The code does align with Chinese TTS generation via a GPT-SoVITS API, so the general TTS portion of the description is accurate. However, the declared description explicitly says 'voice cloning support,' which implies the caller can provide or choose a reference voice. In the code, `ref_audio_path` is fixed to `DEFAULT_REF_AUDIO`, `prompt_text` is empty, and the exported interface only accepts `(text, outputPath, opts)` with no voice/reference-audio input. The header comment also states it is focused on outputting a single '女一号声线' (female voice #1). Therefore, the code does not actually expose voice cloning support as described, making the description materially overstated.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill promotes voice cloning using a pre-recorded reference file but does not warn that the file may contain sensitive biometric voice data. This can lead users to collect, store, or process identifying voice samples without appropriate consent, retention limits, or access controls, creating privacy and compliance risk.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The manifest describes a text-to-speech skill with voice cloning support, but the implementation also invokes a local shell command via child_process/ffmpeg to transform audio. Spawning subprocesses is a materially broader capability than plain TTS API use and is not stated in the skill purpose.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The request parameters force both text_lang and prompt_lang to 'zh', and the file comments describe the skill in Chinese-focused terms. This creates a language/locale policy concern because the skill constrains output to a specific language without user opt-in or an explicit documented justification.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The function sends the input text and reference-audio parameters to the GPT-SoVITS HTTP endpoint via axios, but there is no user-facing notice, confirmation, or warning that user content will be transmitted over HTTP. This is a safety-relevant disclosure gap for network transmission of potentially sensitive user data.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The function writes the generated MP3 to a caller-controlled outputPath with no restriction to a safe directory, no path normalization checks, and no confirmation before overwriting via ffmpeg -y. If untrusted input can reach this parameter, an attacker could overwrite arbitrary files writable by the process.

Natural-Language Policy Violations

Low
Confidence
80% confidence
Finding
The description states 'High-quality Chinese TTS' and later repeats that it converts Chinese text, which imposes a language constraint. Under SQP-3, forcing a specific language without user opt-in can be a policy concern unless the locale restriction is clearly justified or optional.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
index.js:57