Back to skill

Security audit

Voice Agent

Security checks for vulnerabilities and agentic risk

Overview

The skill is purpose-aligned for voice generation, but it gives the agent broad account, voice-cloning, credential, and calling authority with weak scoping and plaintext persistence.

Review carefully before installing. Use only dedicated ElevenLabs/Twilio accounts, scoped tokens, and a dedicated browser profile; avoid putting account passwords or broad auth tokens in .env; require explicit consent for voice cloning and comply with call-recording, telemarketing, and outreach laws before enabling calls.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (4)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:263
Finding
Unpinned Dependencies Installed into the System Python Environment<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 263-264 and 699-700 **Vulnerability Type**: Unsafe third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```bash pip install elevenlabs --break-system-packages pip install requests --break-system-packages ``` The setup checklist also instructs: ```text [ ] pip install elevenlabs --break-system-packages [ ] pip install twilio --break-system-packages (optional) ``` ### Technical Analysis The installation instructions retrieve packages without pinning versions or verifying package hashes. A newly released, compromised, or otherwise malicious dependency version could therefore be installed automatically. Python packages may execute code during installation and subsequently run with all privileges granted to the Python process. The `--break-system-packages` option also bypasses protections intended to prevent `pip` from modifying a system-managed Python environment. This expands the potential effect from the skill's isolated dependencies to other applications using the same interpreter. The package names appear consistent with the declared functionality, and no typosquatted package was identified. The risk arises from the unpinned and system-wide installation process rather than evidence that the named packages are currently malicious. ### Attack Path 1. An attacker compromises the upstream package, its maintainer account, or a transitive dependency. 2. The attacker publishes a malicious version under a package name used by the installation instructions. 3. A user follows the skill instructions and runs the unpinned `pip install` command. 4. `pip` downloads and installs the attacker-controlled version. 5. Installation-time or import-time code executes with the privileges of the user running setup. 6. Because installation targets the system-managed environment, the malicious component may affect this skill and other Python applications using that environment. ...[truncated 370 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a dedicated virtual environment rather than modifying the system Python installation. 2. Pin every direct and transitive dependency to a reviewed version. 3. Use a lock file or requirements file containing cryptographic hashes, for example with `pip install --require-hashes`. 4. Remove `--break-system-packages` from the instructions. 5. Review dependency release history and vulnerability advisories before updating. 6. Run dependency installation and the skill itself as an unprivileged user. 7. Consider building dependencies into a reviewed, reproducible container image. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:143
Finding
ElevenLabs API Credentials Are Persisted Redundantly in Plaintext Files<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 143-146, 319-325, and 420-421; `voice_generator.py`, lines 27-47 **Vulnerability Type**: Plaintext secret storage with unnecessary duplication **Risk Level**: High ### Vulnerable Code `SKILL.md` instructs the agent to store the API key in two locations: ```text → Write to /workspace/voice/config.json: { "ELEVENLABS_API_KEY": "sk_..." } → Also write to .env: ELEVENLABS_API_KEY=sk_... ``` It also appends configuration data to a fixed environment file: ```bash VOICE_ID=$(curl -s -X POST https://api.elevenlabs.io/v1/voices/add -H "xi-api-key: $ELEVENLABS_API_KEY" -F "name=Wesley" -F "files=@/workspace/voice/samples/sample_01.mp3" -F "files=@/workspace/voice/samples/sample_02.mp3" -F "files=@/workspace/voice/samples/sample_03.mp3" | python3 -c "import sys,json; print(json.load(sys.stdin)['voice_id'])") echo "Voice ID: $VOICE_ID" # Write to .env echo "ELEVENLABS_VOICE_ID=$VOICE_ID" >> /docker/openclaw-yyvg/.env echo "✅ ELEVENLABS_VOICE_ID written to .env" ``` The Python implementation reads and writes the plaintext configuration without applying restrictive permissions: ```python def load_config(): if not os.path.exists(CONFIG_FILE): return {} with open(CONFIG_FILE, encoding="utf-8") as f: return json.load(f) def save_config(data): os.makedirs(os.path.dirname(CONFIG_FILE), exist_ok=True) with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump(data, f, indent=2) def get_api_key(): cfg = load_config() key = cfg.get("ELEVENLABS_API_KEY") or os.environ.get("ELEVENLABS_API_KEY") if not key: print("❌ ELEVENLABS_API_KEY not found in config.json or .env") print(" Run voice-agent setup first, or set the key manually.") sys.exit(1) return key ``` ### Technical Analysis The API key is deliberately persisted in both `config.json` and an environment file. This duplication exceeds the minimum ...[truncated 1629 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store the ElevenLabs API key in one secret-management facility only. 2. Keep non-secret identifiers, such as voice IDs, separate from API credentials. 3. If file-based storage is unavoidable, create the file atomically with mode `0600` and verify ownership before use. 4. Do not append secrets to a shared or hardcoded `.env` path. 5. Generate a least-privilege API key restricted to only the endpoints required by this skill. 6. Prevent secret files from entering source control, backups, logs, generated artifacts, and support bundles. 7. Add key rotation and immediate revocation procedures. 8. Avoid storing account passwords in `.env`; use OAuth authorization or a dedicated secret manager. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
voice_generator.py:141
Finding
Predictable Shared Temporary Files Permit Symlink and Concurrency Attacks<![CDATA[ ## Vulnerability Details **File Location**: `voice_generator.py`, lines 141-161 **Vulnerability Type**: Insecure temporary-file creation **Risk Level**: Medium ### Vulnerable Code ```python tmp_files = [] for i, chunk in enumerate(chunks): tmp_path = f"/tmp/voice_chunk_{i:03d}.mp3" print(f" Chunk {i+1}/{len(chunks)}: {len(chunk)} chars") audio_bytes = tts_chunk(api_key, voice_id, chunk, model) with open(tmp_path, "wb") as f: f.write(audio_bytes) tmp_files.append(tmp_path) if len(tmp_files) == 1: import shutil shutil.copy(tmp_files[0], output_path) else: # Concatenate with ffmpeg list_file = "/tmp/voice_concat_list.txt" with open(list_file, "w") as f: for p in tmp_files: f.write(f"file '{p}'\n") ``` ### Technical Analysis The code creates MP3 chunks and an ffmpeg list file under globally predictable names in `/tmp`. It does not use exclusive creation, verify file ownership, reject symbolic links, or isolate files in a process-specific directory. On a multi-user host, another user may pre-create one of these paths as a symbolic link. Opening it with mode `"wb"` follows the link and truncates the target if the skill process can write to that target. Predictable names also cause concurrent TTS processes to overwrite or delete one another's files, potentially mixing generated speech across jobs. The cleanup loop does not eliminate the initial race condition and may itself delete another concurrent process's temporary file. ### Attack Path 1. An attacker who can write to `/tmp` predicts `/tmp/voice_chunk_000.mp3` or `/tmp/voice_concat_list.txt`. 2. The attacker creates a symbolic link from the predictable path to a file writable by the victim process. 3. A more privileged user runs the TTS command. 4. Python opens the path with `"wb"` and follows the symbolic link. 5. The linked target is truncated or overwritten with generated MP3 or ffmpeg-list data. Alternatively: 1. Two leg ...[truncated 520 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create a private temporary directory with `tempfile.TemporaryDirectory()`. 2. Place all chunk files and the concat list inside that directory. 3. Use secure exclusive creation APIs rather than predictable global filenames. 4. Ensure cleanup occurs in a `finally` block or through the temporary-directory context manager. 5. Run the program as an unprivileged user. 6. Validate the output destination separately and reject symbolic-link destinations where appropriate. 7. Add concurrent-generation tests to confirm that parallel jobs remain isolated. Example approach: ```python import tempfile from pathlib import Path with tempfile.TemporaryDirectory(prefix="voice-agent-") as temp_dir: temp_root = Path(temp_dir) tmp_path = temp_root / f"chunk_{i:03d}.mp3" list_file = temp_root / "concat.txt" ``` ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
SKILL.md:103
Finding
Autonomous Setup Reuses an Authenticated Google Browser Session and Creates Credentials<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 103-145 and 382-421 **Vulnerability Type**: Excessive authenticated browser privileges during automated setup **Risk Level**: High ### Vulnerable Instructions ```text OPTION A — Google OAuth (preferred — zero credentials required) Condition: virtual-desktop has an active Google session Process: 1. virtual-desktop opens https://elevenlabs.io/app/sign-in 2. Clicks "Continue with Google" 3. Google session is already active in the browser 4. ElevenLabs dashboard loads automatically 5. Proceed to API key creation ``` The workflow then directs the agent to create and persist a credential: ```text Navigation path (2026 ElevenLabs UI): Dashboard → bottom-left corner → "Developers" → Tab "API Keys" → Button "Create API Key" → Name: "wesley-agent" → Click "Create" → Copy the generated key (shown only once) → Write to /workspace/voice/config.json: { "ELEVENLABS_API_KEY": "sk_..." } → Also write to .env: ELEVENLABS_API_KEY=sk_... ``` The browser instructions further specify: ```text OPTION A (Google OAuth): → Wait for page to load → Click button: "Continue with Google" → Google session auto-completes the login → Dashboard loads at: https://elevenlabs.io/app/home ``` ### Technical Analysis TTS generation requires an ElevenLabs API key, but it does not inherently require autonomous control of a browser profile containing an active Google session. Reusing that session grants the desktop automation agent the ability to act within an authenticated identity context during setup. The workflow also authorizes the agent to create a new API credential, copy its value, and persist it without an explicit confirmation boundary. This exceeds the minimum privilege required for normal TTS execution and combines browser-session authority, account configuration authority, and local secret-writing authority in one automated flow. No code in the reviewed project de ...[truncated 1634 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make manual provisioning of a scoped ElevenLabs API key the default setup path. 2. Require explicit user confirmation immediately before OAuth authorization, API-key creation, voice-sample upload, and Twilio connection. 3. Use a dedicated browser profile containing no unrelated authenticated sessions. 4. Display the exact target domain and requested OAuth permissions before continuing. 5. Restrict virtual-desktop navigation to an allowlist of exact ElevenLabs URLs. 6. Create a least-privilege API key and clearly show its permissions to the user. 7. Separate account bootstrap from routine TTS execution so normal operation never needs browser-session access. 8. Record an auditable account-change event without logging the resulting secret. 9. Provide a documented procedure for reviewing and revoking automatically created keys. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (43)

Credential Access

High
Category
Privilege Escalation
Content
```
Minimum (TTS only):
  → Google connected in virtual-desktop, OR email/password in .env
  → 3 MP3 voice samples in /workspace/voice/samples/

For calls (add):
Confidence
84% confidence
Finding
The README instructs users to place sensitive credentials in a .env file for automated use, while the broader skill is designed to self-configure external services and make calls. Although using .env is common, in this context it increases the risk of credential exposure, overbroad reuse by the agent, or accidental leakage through logs, workspace access, or downstream automation.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The code's real primary function is narrower than the description: it generates TTS audio using an existing ElevenLabs API key and voice ID, reports status, and summarizes/list call-related JSON records. There is no code for cloning voices, creating/managing an ElevenLabs conversational agent, integrating with Twilio APIs, placing or answering calls, or navigating a website/virtual desktop to self-configure credentials. The call-related functionality is limited to reading pending/history files from disk, not executing telephony actions. Thus the description materially overstates the implemented capabilities and setup behavior.

Missing User Warnings

High
Confidence
95% confidence
Finding
The skill promotes voice cloning, automated calling, transcript collection, and reporting without a prominent upfront warning about consent, legal compliance, and biometric/privacy sensitivity. In this context, missing warnings materially increase the chance of unsafe or unauthorized impersonation and recording workflows.

Credential Access

High
Category
Privilege Escalation
Content
Navigates elevenlabs.io autonomously via virtual-desktop
  Logs in via Google OAuth or email/password
  Creates API key, clones voice, configures agent
  Writes all credentials to .env automatically

LAYER 2 — TEXT TO SPEECH
  Converts any text to MP3 using Wesley's cloned voice
Confidence
98% confidence
Finding
The skill explicitly automates credential retrieval and writes all credentials to .env automatically. That encourages collection, persistence, and reuse of secrets in a broadly accessible format, which is dangerous in any agent environment.

Credential Access

High
Category
Privilege Escalation
Content
5. Proceed to API key creation

OPTION B — Email / Password
  Condition: ELEVENLABS_EMAIL and ELEVENLABS_PASSWORD in .env

  Process:
  1. virtual-desktop opens https://elevenlabs.io/app/sign-in
Confidence
90% confidence
Finding
The skill instructs reading ElevenLabs email/password from .env for automated login. Using stored account passwords for browser automation increases blast radius if the environment or logs are exposed.

Credential Access

High
Category
Privilege Escalation
Content
### Step 5 — Create Conversational Agent (optional — for calls)

```
Only runs if TWILIO_ACCOUNT_SID is in .env

Navigation path:
  Dashboard → "Agents" → "Create Agent"
Confidence
89% confidence
Finding
The skill depends on reading Twilio credentials from .env to configure telephony features. These credentials can enable call placement, messaging, and account changes, so storing and consuming them this way creates substantial account-compromise risk.

External Script Fetching

High
Category
Supply Chain
Content
#### Step 2 — Verify API key works

```bash
curl -s https://api.elevenlabs.io/v1/user   -H "xi-api-key: $ELEVENLABS_API_KEY" | python3 -m json.tool
# Expected: JSON with subscription info
# If 401 error: API key is wrong or expired
```
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
print(f"✅ Voice ID saved to config.json")
```

#### Step 3 — Clone via curl (alternative)

```bash
# Clone with multiple files
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
# { "voice_id": "abc123...", "name": "Wesley" }

# Extract and save the voice_id
VOICE_ID=$(curl -s -X POST https://api.elevenlabs.io/v1/voices/add   -H "xi-api-key: $ELEVENLABS_API_KEY"   -F "name=Wesley"   -F "files=@/workspace/voice/samples/sample_01.mp3"   -F "files=@/workspace/voice/samples/sample_02.mp3"   -F "files=@/workspace/voice/samples/sample_03.mp3"   | python3 -c "import sys,json; print(json.load(sys.stdin)['voice_id'])")

echo "Voice ID: $VOICE_ID"
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
echo "Voice ID: $VOICE_ID"

# Write to .env
echo "ELEVENLABS_VOICE_ID=$VOICE_ID" >> /docker/openclaw-yyvg/.env
echo "✅ ELEVENLABS_VOICE_ID written to .env"
```
Confidence
99% confidence
Finding
This instruction appends data into a global .env file, normalizing direct secret/state persistence outside the skill boundary. Such patterns commonly lead to secret leakage, accidental reuse, and privilege spread across tasks.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill directs writing sensitive identifiers into a global .env file outside the declared workspace, which bypasses the skill's stated boundary and persists secrets in a broader shared location. This can expose credentials to unrelated processes, users, or later tasks.

Scope Creep

High
Confidence
99% confidence
Finding
Appending ELEVENLABS_VOICE_ID to /docker/openclaw-yyvg/.env violates the declared permission model and normalizes writing agent-derived state into a global environment file. While a voice ID is less sensitive than an API key, the out-of-scope write still breaks containment and can facilitate later misuse.

Credential Access

High
Category
Privilege Escalation
Content
echo "Voice ID: $VOICE_ID"

# Write to .env
echo "ELEVENLABS_VOICE_ID=$VOICE_ID" >> /docker/openclaw-yyvg/.env
echo "✅ ELEVENLABS_VOICE_ID written to .env"
```
Confidence
99% confidence
Finding
Even though the specific value here is a voice ID, the pattern is still credential/state persistence in a global environment file. It creates an unsafe precedent and broadens access to data generated by the skill.

Credential Access

High
Category
Privilege Escalation
Content
# Write to .env
echo "ELEVENLABS_VOICE_ID=$VOICE_ID" >> /docker/openclaw-yyvg/.env
echo "✅ ELEVENLABS_VOICE_ID written to .env"
```

#### Step 4 — List all voices (verify clone appears)
Confidence
99% confidence
Finding
The repeated instruction confirming write to .env reinforces unsafe secret-handling behavior and indicates persistence of operational data in a shared global location. This compounds risk of later disclosure or misuse.

External Script Fetching

High
Category
Supply Chain
Content
#### Step 4 — List all voices (verify clone appears)

```bash
# Via curl
curl -s https://api.elevenlabs.io/v1/voices   -H "xi-api-key: $ELEVENLABS_API_KEY"   | python3 -c "
import sys, json
data = json.load(sys.stdin)
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
→ If login fails: log to ERRORS.md, notify principal
```

#### Step 2 — Get API Key from dashboard

```
Navigation path (2026 UI):
Confidence
97% confidence
Finding
The documented step to 'Get API Key from dashboard' instructs the agent to retrieve a credential directly from a provider UI. This is credential harvesting behavior, and in the context of autonomous browser control it is particularly dangerous because it bypasses normal user-mediated secret handling.

Credential Access

High
Category
Privilege Escalation
Content
→ Or: find input with type="password" that appears after creation
  8. Save immediately:
     → Write to /workspace/voice/config.json
     → Write to /docker/openclaw-yyvg/.env as ELEVENLABS_API_KEY=sk_...

  Direct URL shortcut: https://elevenlabs.io/app/settings/api-keys
```
Confidence
99% confidence
Finding
This step instructs capturing a newly created API key from the dashboard and writing it to /docker/openclaw-yyvg/.env. Harvesting and persisting one-time-visible secrets into a global file is a serious credential-handling weakness.

Scope Creep

High
Confidence
99% confidence
Finding
Documented behavior writes ELEVENLABS_API_KEY to /docker/openclaw-yyvg/.env, which is outside declared write permissions. That is a boundary violation and creates secret persistence in a sensitive global location.

Credential Access

High
Category
Privilege Escalation
Content
→ Click the three-dot menu "⋯" on the voice card
      → Click "Copy Voice ID"
      → Or find in URL: elevenlabs.io/app/voice-lab/[VOICE_ID]
  12. Save to config.json + .env

  Direct URL shortcut: https://elevenlabs.io/app/voice-lab
```
Confidence
86% confidence
Finding
Saving identifiers to both config.json and .env broadens storage locations unnecessarily. Duplicating operational state across files increases exposure and complicates revocation and auditing.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
→ Background noise in samples
  → Multiple speakers in same file
  Solution:
  → Delete the bad clone: DELETE /v1/voices/{voice_id}
    curl -X DELETE https://api.elevenlabs.io/v1/voices/$VOICE_ID       -H "xi-api-key: $ELEVENLABS_API_KEY"
  → Record new samples (quieter environment, longer duration)
  → Re-run cloning process
Confidence
90% confidence
Finding
The skill documents a direct DELETE operation on externally hosted voice resources with a variable identifier and no confirmation or ownership checks. In an agent setting, destructive API actions without validation can delete the wrong asset or be abused through parameter manipulation.

External Script Fetching

High
Category
Supply Chain
Content
→ Multiple speakers in same file
  Solution:
  → Delete the bad clone: DELETE /v1/voices/{voice_id}
    curl -X DELETE https://api.elevenlabs.io/v1/voices/$VOICE_ID       -H "xi-api-key: $ELEVENLABS_API_KEY"
  → Record new samples (quieter environment, longer duration)
  → Re-run cloning process
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Credential Access

High
Category
Privilege Escalation
Content
PROBLEM: "Invalid API key" (401)
  Solution: Regenerate key in dashboard
  Direct URL: https://elevenlabs.io/app/settings/api-keys
  Update config.json and .env with new key

PROBLEM: ffmpeg not found for audio concatenation
  Solution:
Confidence
92% confidence
Finding
Telling the operator to update config.json and .env with regenerated API keys extends the same insecure credential lifecycle pattern. Reissued keys remain vulnerable if stored in plaintext local files.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
GET  /v1/voices             → list all voices
POST /v1/voices/add         → create IVC clone (multipart form)
GET  /v1/voices/{id}        → get voice details
DELETE /v1/voices/{id}      → delete a voice
POST /v1/text-to-speech/{id} → generate audio (JSON body)
GET  /v1/models             → list available models
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Credential Access

High
Category
Privilege Escalation
Content
```
MINIMUM (TTS only — no calls):
  Option A: Google account connected in virtual-desktop browser
  Option B: ELEVENLABS_EMAIL + ELEVENLABS_PASSWORD in .env
  + 3 MP3 voice samples in /workspace/voice/samples/

FOR CALLS (add Twilio):
Confidence
83% confidence
Finding
The setup guidance normalizes storing ElevenLabs email/password in .env as a standard option. That encourages weak secret hygiene for primary account credentials instead of safer delegated access methods.

Credential Access

High
Category
Privilege Escalation
Content
→ Save as MP3 (any quality works for IVC)
   → Upload to /workspace/voice/samples/

3. (Optional) Add Twilio credentials to .env for calls

4. Run voice-agent — it configures itself automatically
Confidence
83% confidence
Finding
The instruction to add Twilio credentials to .env for calls encourages storing highly sensitive telephony credentials in plaintext configuration. If exposed, attackers could place calls/messages, access logs, or reconfigure account assets.

Static analysis

Detected: suspicious.prompt_injection_instructions

Prompt-injection style instruction pattern detected.

Warn
Code
suspicious.prompt_injection_instructions
Location
SKILL.md:185