Back to skill

Security audit

Local TTS

Security checks for vulnerabilities and agentic risk

Overview

This skill appears purpose-built for local text-to-speech, but its privacy and safety claims overstate what the artifacts actually do.

Install only if you are comfortable managing Python and model supply-chain risk yourself. Use an isolated virtual environment or container, pin and verify dependencies and model revisions where possible, avoid processing highly sensitive text unless console logs are controlled, and use voice cloning only with explicit permission from the speaker.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T08 · Insecure Dependencies

Warning
Location
scripts/tts_linux.py:117
Finding

Unpinned Third-Party Dependencies and Mutable Model Artifacts

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:29-32, SKILL.md:42-43, references/linux_windows_transformers.md:34-48, references/macos_mlx_audio.md:29-33, scripts/tts_linux.py:117-118
Vulnerability Type: Supply-chain risk caused by unpinned executable dependencies and model revisions
Risk Level: Medium

Vulnerable Code and Instructions

SKILL.md:29-32:

bash
pip install mlx-audio
brew install ffmpeg

SKILL.md:42-43:

bash
pip install qwen-tts

references/linux_windows_transformers.md:34-48:

bash
pip install qwen-tts
bash
pip install flash-attn --no-build-isolation

scripts/tts_linux.py:117-118:

python
model = Qwen3TTSModel.from_pretrained(model_id, **model_kwargs)
tokenizer = Qwen3TTSTokenizer.from_pretrained(model_id)

Technical Analysis

The installation instructions resolve the latest available versions of mlx-audio, qwen-tts, and flash-attn rather than versions reviewed and approved by the project. No lock file, package hashes, constraints file, or integrity-verification procedure is supplied.

The FlashAttention command additionally disables build isolation. This can allow its build process to interact with packages already installed in the active Python environment and makes the result more dependent on mutable local and upstream state.

The Linux wrapper loads models and tokenizers from repository identifiers without pinning immutable repository revisions. The macOS backend likewise receives mutable model identifiers through its command line. These operations can initiate network downloads on first use, despite prominent claims that the Skill has no external dependencies and requires no network.

There is no evidence that any currently referenced package or model is malicious. The vulnerability is the absence of controls ensuring that future installations retrieve the same reviewed code and artifacts.

Attac

...[truncated 1386 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin every Python dependency to an exact reviewed version in a requirements or lock file.
  2. Use hash-checked installation, such as pip install --require-hashes -r requirements.txt.
  3. Maintain separate dependency sets for macOS and Linux/Windows, including all transitive dependencies.
  4. Avoid --no-build-isolation where possible. If it is unavoidable, document why it is needed and build from a verified source in a disposable environment.
  5. Pin Hugging Face and MLX model repositories to immutable commit revisions rather than mutable repository heads.
  6. Record and verify checksums for model files used in high-assurance or air-gapped environments.
  7. Install and run the Skill in an unprivileged virtual environment or container.
  8. Clearly disclose that package installation and initial model acquisition require network access.
  9. Provide an explicit offline installation procedure using preverified package wheels and model artifacts.
  10. Add automated dependency and artifact provenance checks to release testing.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/tts_macos.py:39
Finding

Sensitive TTS Input and Reference Text Exposed Through Console Logging

Content
View full analysis

Vulnerability Details

File Location: scripts/tts_macos.py:39-71, scripts/tts_linux.py:174-176
Vulnerability Type: Plaintext disclosure of potentially sensitive user-provided content
Risk Level: Medium

Vulnerable Code

scripts/tts_macos.py:39-71:

python
def run_tts(args):
    """Run TTS with the given arguments."""
    
    # Build command
    cmd = [
        sys.executable, "-m", "mlx_audio.tts.generate",
        "--text", args.text,
        "--model", MODELS.get(args.model, args.model),
    ]
    
    # Add output path
    if args.output:
        cmd.extend(["--output", args.output])
    
    # Add voice (CustomVoice)
    if args.voice:
        cmd.extend(["--voice", args.voice])
    
    # Add instruct (VoiceDesign)
    if args.instruct:
        cmd.extend(["--instruct", args.instruct])
    
    # Add reference audio for cloning
    if args.ref_audio:
        cmd.extend(["--ref_audio", args.ref_audio])
    if args.ref_text:
        cmd.extend(["--ref_text", args.ref_text])
    
    # Add parameters
    if args.speed is not None:
        cmd.extend(["--speed", str(args.speed)])
    if args.gender:
        cmd.extend(["--gender", args.gender])
    if args.pitch is not None:
        cmd.extend(["--pitch", str(args.pitch)])
    if args.lang_code:
        cmd.extend(["--lang_code", args.lang_code])
    
    print(f"Running: {' '.join(cmd)}")
    result = subprocess.run(cmd)

scripts/tts_linux.py:174-176:

python
# Tokenize input
print(f"Synthesizing: '{args.text[:50]}{'...' if len(args.text) > 50 else ''}'")
inputs = tokenizer(args.text, return_tensors="pt").to(device)

Technical Analysis

The macOS wrapper constructs a command containing the complete synthesis text and, when supplied, the complete reference transcript. It then joins and prints every command argument. Voice instructions and local reference-audi ...[truncated 2171 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove synthesis text, reference transcripts, instructions, and file paths from default console output.

  2. Replace the macOS command dump with a non-sensitive message such as:

    python
    print("Starting local TTS generation")
    
  3. Replace the Linux preview with a message that reports only non-sensitive metadata, if necessary:

    python
    print(f"Synthesizing local text input ({len(args.text)} characters)")
    
  4. Add an explicit --verbose or --debug option for diagnostic logging, disabled by default.

  5. Even in debug mode, redact synthesis text, reference transcripts, and sensitive path components.

  6. Document that verbose console output may be retained by the execution environment.

  7. Add tests asserting that supplied synthesis text and reference text never appear in standard output or standard error.

  8. Revise the “No usage logs” claim to describe both application behavior and the possibility of host-level output capture accurately.

Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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 (18)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill advertises shell-based installation and execution flows and references local scripts, but it declares no explicit tool scope such as permissions or allowed-tools. In an agent ecosystem, this can cause the skill to run with broader-than-expected capabilities or without clear operator awareness, increasing the risk of unintended command execution or file access.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill includes voice cloning instructions using reference audio but provides no warning about consent, impersonation, or lawful and ethical use. This lowers friction for misuse such as cloning another person's voice without permission, enabling social engineering, fraud, or deceptive content generation.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/linux_windows_transformers.md (reported line 69)May include surrounding context.

Ubuntu/Debian:

bash
sudo apt update
sudo apt install ffmpeg

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/linux_windows_transformers.md (reported line 70)May include surrounding context.

Ubuntu/Debian:

bash
sudo apt update
sudo apt install ffmpeg

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The document provides concrete voice cloning instructions using ref_audio and ref_text but does not include any warning about consent, impersonation risk, or lawful use of biometric voice data. In a privacy-first local TTS skill, this omission materially increases misuse risk because the feature enables realistic speech generation from a reference sample without any guardrails or user notice.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation includes a voice cloning workflow using reference audio and transcript text without any warning about consent, impersonation risk, or handling of sensitive biometric data. In a privacy- and security-themed local TTS skill, this omission can normalize unsafe use and increase the likelihood of non-consensual cloning or misuse of personal voice samples.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script is presented as privacy-first local/offline TTS, but from_pretrained will fetch model artifacts from Hugging Face when they are not already cached. That creates unexpected network access, metadata leakage, and supply-chain exposure that contradict the offline/local trust model users may rely on.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The script exposes voice cloning from reference audio without any warning about consent, biometric privacy, or misuse. In a TTS skill explicitly advertising realistic voice cloning, omission of these safeguards makes social engineering, impersonation, and privacy abuse more likely in practical use.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/tts_macos.py (reported line 71)May include surrounding context.

python
cmd.extend(["--lang_code", args.lang_code])
    
    print(f"Running: {' '.join(cmd)}")
    result = subprocess.run(cmd)
    return result.returncode

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · tests/test_integration.py (reported line 59)May include surrounding context.

python
'--output', output_path
            ]
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
            
            # Check command succeeded
            self.assertEqual(result.returncode, 0,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · tests/test_integration.py (reported line 133)May include surrounding context.

python
'--output', output_path
            ]
            
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
            
            # Note: This may fail in CI without GPU, so we just check it runs
            # without crashing (return code 0 means success)

compile() call detected

Medium
Category
Dangerous Code Execution
Confidence
65% confidence
Finding

compile() creates code objects from strings. When combined with exec()/eval(), it enables obfuscated code execution.

Content

Scanner excerpt · tests/test_integration.py (reported line 83)May include surrounding context.

python
with open(script_path, 'r', encoding='utf-8') as f:
            code = f.read()
        # Should compile without errors
        compile(code, script_path, 'exec')
    
    def test_tts_linux_imports(self):
        """Test that tts_linux.py is valid Python syntax."""

compile() call detected

Medium
Category
Dangerous Code Execution
Confidence
65% confidence
Finding

compile() creates code objects from strings. When combined with exec()/eval(), it enables obfuscated code execution.

Content

Scanner excerpt · tests/test_integration.py (reported line 158)May include surrounding context.

python
with open(script_path, 'r', encoding='utf-8') as f:
            code = f.read()
        # Should compile without errors
        compile(code, script_path, 'exec')
    
    def test_tts_linux_imports(self):
        """Test that tts_linux.py is valid Python syntax."""

compile() call detected

Medium
Category
Dangerous Code Execution
Confidence
65% confidence
Finding

compile() creates code objects from strings. When combined with exec()/eval(), it enables obfuscated code execution.

Content

Scanner excerpt · tests/test_unit.py (reported line 26)May include surrounding context.

python
with open(script_path, 'r', encoding='utf-8') as f:
            code = f.read()
        # Should compile without errors
        compile(code, script_path, 'exec')
    
    def test_tts_linux_imports(self):
        """Test that tts_linux.py is valid Python syntax."""

compile() call detected

Medium
Category
Dangerous Code Execution
Confidence
65% confidence
Finding

compile() creates code objects from strings. When combined with exec()/eval(), it enables obfuscated code execution.

Content

Scanner excerpt · tests/test_unit.py (reported line 34)May include surrounding context.

python
with open(script_path, 'r', encoding='utf-8') as f:
            code = f.read()
        # Should compile without errors
        compile(code, script_path, 'exec')
    
    def test_tts_linux_imports(self):
        """Test that tts_linux.py is valid Python syntax."""

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
98% confidence
Finding

DEFAULT_MALE_VOICE is set to Aiden, and the synthesis logic uses that constant when --male is selected. However, the CLI help text states --male uses the default male voice (Ryan), which directly contradicts the actual behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The --lang_code argument defaults to "en-US", which imposes a specific locale unless the user explicitly overrides it. The file does not present this as a user choice at startup or justify the locale constraint as region-specific behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The --lang_code argument is assigned a default of en-US, which imposes a specific language/locale unless the user notices and overrides it. This is a natural-language policy concern because the skill selects a locale by default rather than prompting for or offering a neutral opt-in choice.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.