Back to skill

Security audit

Miranda ElevenLabs Speech (TTS/STT)

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised ElevenLabs speech tasks, but it reads an overbroad parent .env file and sends user text or audio to ElevenLabs without enough privacy warning.

Review before installing. Use only non-sensitive text or audio unless you are comfortable sending it to ElevenLabs, store ELEVENLABS_API_KEY securely, and be aware that the TTS script may read a parent .env file outside the skill directory. There is no evidence of destructive behavior, persistence, hidden command execution, or unrelated data exfiltration.

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

Warning
Location
scripts/elevenlabs_speech.py:5
Finding
Unnecessarily Broad Loading of an Ancestor .env File## Vulnerability Details **File Location**: `scripts/elevenlabs_speech.py`, lines 5-8 **Vulnerability Type**: Insecure environment configuration and excessive secret exposure **Risk Level**: Medium ### Vulnerable Code ```python from dotenv import load_dotenv # Load environment variables from workspace .env load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '..', '..', '.env')) ``` ### Technical Analysis The module automatically loads an `.env` file by traversing three parent directories from `scripts/elevenlabs_speech.py`. From the audited project layout, this resolves outside the Skill's project directory rather than to the documented workspace-root `.env`. `load_dotenv()` parses all variables in that external file and adds them to the process environment, even though this Skill only needs `ELEVENLABS_API_KEY`. Loading an unrelated ancestor configuration file therefore exceeds the minimum privilege and data-access scope required for the declared text-to-speech functionality. The behavior occurs as an import-time side effect, so merely importing `ElevenLabsClient` triggers the external configuration read. The code does not transmit arbitrary loaded variables, and the reviewed network requests send only the ElevenLabs API key and functionality-specific text or request data. Nevertheless, the broad load exposes unrelated configuration values to the process and can cause the client to use an unintended API credential. ### Attack Path 1. An attacker or another local project gains the ability to create or modify the `.env` file at the hardcoded ancestor path. 2. A user executes the script or imports `scripts.elevenlabs_speech`. 3. The import-time `load_dotenv()` call reads every variable from the attacker-controlled or unrelated file into the process environment. 4. If `ELEVENLABS_API_KEY` was not already defined, the injected value becomes available to `ElevenLabsClient`. 5. The client authenticates ElevenLabs requests using that uninten ...[truncated 1066 chars]
Remediation
## Remediation Suggestions 1. Remove import-time loading of an `.env` file outside the project. 2. Prefer a credential supplied explicitly to `ElevenLabsClient` or inherited from the already configured process environment. 3. If `.env` support is required, resolve it against an explicit and validated project/workspace root rather than traversing ancestor directories. 4. Parse and retain only `ELEVENLABS_API_KEY` instead of importing all entries into the process environment. 5. Do not override an existing environment value, and fail closed with a clear error when the key is absent. 6. Restrict the `.env` file's permissions to its owner and document its exact expected location. 7. Move configuration loading into the CLI entry point so importing the client library does not read external files as a side effect. A safer pattern is: ```python from pathlib import Path from dotenv import dotenv_values import os PROJECT_ROOT = Path(__file__).resolve().parents[1] config = dotenv_values(PROJECT_ROOT / ".env") api_key = os.getenv("ELEVENLABS_API_KEY") or config.get("ELEVENLABS_API_KEY") if not api_key: raise ValueError("ELEVENLABS_API_KEY is required") ```
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (17)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The supplied code is narrowly focused on speech-to-text. It reads an audio file from disk and sends it to ElevenLabs' /speech-to-text endpoint with transcription-related options such as language, speaker count, and timestamp granularity. There is no text-to-speech functionality, no endpoint for voice synthesis, and no handling of text input for conversion into audio. The speech-to-text portion of the description is accurate, but the overall declared purpose overstates the implemented capabilities by claiming both TTS and STT.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code accurately supports part of the description: high-quality text-to-speech using ElevenLabs and listing available voices. However, it does not contain any code for uploading audio, transcribing speech, handling voice messages, or performing speech-to-text. The primary mismatch is that the declared description presents the skill as both TTS and STT, while the implementation is TTS-only plus voice enumeration. Loading an API key from a .env file and making outbound requests to ElevenLabs are consistent supporting details, not separate mismatches.

Credential Access

High
Category
Privilege Escalation
Content
from pathlib import Path
from dotenv import load_dotenv

# Load environment variables from workspace .env
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '..', '..', '.env'))

class ElevenLabsClient:
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
from dotenv import load_dotenv

# Load environment variables from workspace .env
load_dotenv(dotenv_path=os.path.join(os.path.dirname(__file__), '..', '..', '..', '.env'))

class ElevenLabsClient:
    """Client for ElevenLabs Text-to-Speech API"""
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill documents use of environment variables for an API key and remote ElevenLabs API calls, but it declares no tool scope or permissions. This creates an undeclared capability boundary where the agent may access secrets and make network requests without transparent authorization, increasing the risk of unintended data egress or misuse in environments that rely on manifest-declared restrictions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill encourages sending user text and audio to ElevenLabs for TTS/STT but does not clearly warn that potentially sensitive content leaves the local environment and is processed by a third-party service. In an agent context, this can lead to inadvertent disclosure of private conversations, voice biometrics, or regulated data because users and integrators are not prompted to assess data-handling risks.

External Transmission

Medium
Category
Data Exfiltration
Content
def __init__(self, api_key=None):
        self.api_key = api_key or os.getenv('ELEVENLABS_API_KEY')
        self.base_url = "https://api.elevenlabs.io/v1"
    
    def transcribe(self, audio_file_path, language_code=None, tag_audio_events=True, 
                   num_speakers=None, timestamps_granularity="word"):
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
def __init__(self, api_key=None):
        self.api_key = api_key or os.getenv('ELEVENLABS_API_KEY')
        self.base_url = "https://api.elevenlabs.io/v1"
    
    def transcribe(self, audio_file_path, language_code=None, tag_audio_events=True, 
                   num_speakers=None, timestamps_granularity="word"):
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code uploads the entire user-supplied audio file to ElevenLabs' external speech-to-text API, which can expose sensitive voice content, background speech, or embedded personal data to a third party. In this skill context, external transmission is expected for cloud transcription, but the lack of explicit user-facing notice or consent still creates a real privacy and data-handling risk.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The manifest describes both Text-to-Speech and Speech-to-Text capabilities, including transcribing voice messages, but this file only provides a text_to_speech method and a get_voices helper. There is no speech-to-text, transcription, or audio-input handling logic anywhere in the implementation or CLI.

External Transmission

Medium
Category
Data Exfiltration
Content
}
        
        try:
            response = requests.post(url, headers=headers, json=payload, timeout=60)
            response.raise_for_status()
            
            # Save audio file
Confidence
87% confidence
Finding
The code transmits user-supplied text to an external network service, which creates a genuine data exposure boundary. In the context of a speech generation skill this behavior is core functionality, so it is not malicious, but it is still a real privacy/security concern if sensitive text can be sent without clear notice or policy controls.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
User-provided text is sent to a third-party API, which can expose sensitive or private content if users are not clearly informed that their input leaves the local environment. In a speech skill, external transmission is expected, but the absence of explicit disclosure and consent still creates a real privacy risk, especially if users paste secrets, personal data, or proprietary text.

Missing User Warnings

Low
Confidence
87% confidence
Finding
The setup instructions require a live API credential but do not warn that the key is sensitive or advise secure storage practices. This increases the chance of accidental exposure through checked-in .env files, logs, shell history, or copied examples, which can enable unauthorized use of the ElevenLabs account.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The code accesses an API credential from the environment, which falls under sensitive credential handling. The file does not include any warning, comment, or user-facing notice explaining that an external service credential is required and will be used for authenticated requests.

Intent-Code Divergence

Low
Confidence
80% confidence
Finding
The class docstring says this is a client for the ElevenLabs Text-to-Speech API, but the class also includes get_voices(), which accesses a separate voice-listing capability. This is a documentation-to-code mismatch in stated intent, even though the extra capability is related to the same service.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The client reads `ELEVENLABS_API_KEY` from the environment and uses it in outbound HTTP headers. Although this is functionally necessary, the file lacks a clear warning or note to users that the skill depends on a sensitive credential and will use it for external API calls.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The code writes API response content to `output_path`, modifying the local filesystem. Although the CLI exposes an `--output` argument, there is no explicit notice in the docstring, help text, or runtime messaging that the operation creates or overwrites a local file.