Back to skill

Security audit

tts

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real text-to-speech skill, but users should review it because it sends text to an online TTS service and has dependency and temporary-file risks.

Install only if you are comfortable with requested text being sent to Microsoft Edge's online TTS service. Avoid converting secrets, private messages, regulated data, or proprietary content. Prefer explicit TTS requests, choose an intentional output path for sensitive audio, clean up generated files, and update or audit npm dependencies before using this in automation.

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/tts-converter.js:19
Finding
Unsafe Shared Temporary Directory for Generated Audio## Vulnerability Details **File Location**: `scripts/tts-converter.js`, lines 19, 52–72, and 126–129 **Vulnerability Type**: Unsafe temporary-file handling **Risk Level**: Medium ### Vulnerable Code ```javascript const TEMP_DIR = path.join(os.tmpdir(), 'edge-tts-temp'); ``` ```javascript async function ensureTempDir() { try { await fs.access(TEMP_DIR); } catch (error) { await fs.mkdir(TEMP_DIR, { recursive: true }); } } /** * Generate unique temporary file path * @param {string} extension - File extension (e.g., '.mp3') * @returns {string} Temporary file path */ function generateTempPath(extension = '.mp3') { const timestamp = Date.now(); const random = Math.random().toString(36).substring(2, 8); const filename = `tts_${timestamp}_${random}${extension}`; return path.join(TEMP_DIR, filename); } ``` ```javascript // Ensure temp directory exists and use temp file if no output path specified await ensureTempDir(); const finalOutputPath = outputPath || generateTempPath('.mp3'); ``` ### Technical Analysis The application stores generated audio in a fixed directory under the operating system's shared temporary directory. It checks only whether that path is accessible; it does not verify that the directory is owned by the current user, has restrictive permissions, or is not a symbolic link. The `fs.access()` followed by `fs.mkdir()` sequence also introduces a time-of-check/time-of-use window. If the directory already exists, the application accepts it without validating its type or security properties. A local attacker may therefore pre-create or manipulate the shared path before the victim invokes the converter. Temporary filenames combine the current timestamp with six characters generated by `Math.random()`. This is not a cryptographically secure source of randomness. Although exploitation requires local access and successful prediction or racing, monitoring the ...[truncated 1937 chars]
Remediation
## Remediation Suggestions 1. Create a private directory for each invocation using `fs.mkdtemp()` beneath `os.tmpdir()` rather than reusing a global directory. 2. Explicitly restrict the directory to the current user with mode `0700`. 3. Use `crypto.randomUUID()` or `crypto.randomBytes()` instead of `Math.random()` for output names. 4. Validate temporary paths with `fs.lstat()` and reject symbolic links or unexpected filesystem object types. 5. Where possible, create output files atomically with exclusive-create and no-follow semantics. 6. Apply restrictive file permissions such as `0600` to generated audio and subtitle files. 7. Delete temporary files and their per-run directory in a `finally` block after the calling application has delivered or copied the result. 8. If files must persist, require an explicit user-selected output path and document the retention and confidentiality implications. 9. Add tests that pre-create the temporary path as a symbolic link, directory owned by another user, and conflicting output file to ensure the converter fails securely.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (20)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared description presents this as a text-to-speech conversion skill that generates spoken audio from text. However, the supplied code only manages persistent user preferences for a TTS system: it loads/saves JSON config, exposes CLI options to set voice/language/rate/pitch/volume, toggles subtitle preferences, handles proxy/timeout, and prints equivalent CLI args. While these settings are related to TTS, the code chunk itself does not accept text input for synthesis, invoke node-edge-tts, generate audio, or create subtitle files. Its primary purpose is materially different: configuration management rather than TTS conversion. The file-system persistence behavior is also an undeclared capability, though it is supportive of the config-manager role.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
97% confidence
Finding
The lockfile pins the transitive dependency ws to version 8.19.0, and the provided advisories indicate this version is affected by an uninitialized memory disclosure and a memory-exhaustion denial-of-service issue. In a TTS skill that relies on node-edge-tts and therefore network/WebSocket communication, processing attacker-controlled or remote service traffic could expose memory contents or allow resource exhaustion, making this a real supply-chain risk rather than a false positive.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation instructs users to install and use a cloud-backed TTS tool but does not clearly warn that user-supplied text is transmitted to an external online service. This can cause accidental disclosure of sensitive prompts, personal data, or confidential content because users may reasonably assume text processing is local unless told otherwise.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The trigger guidance is broad enough that normal discussion of accessibility, multitasking, driving, or cooking could cause the skill to activate and send unintended text to TTS processing. Because this skill uses an online third-party service, accidental invocation can expose user content externally and generate audio actions the user did not explicitly request.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill uses Microsoft Edge’s online TTS service, but the primary description and trigger flow do not clearly warn that input text leaves the local environment. This creates a privacy and data-handling risk, especially if users ask to vocalize sensitive messages, summaries, or search results under the assumption processing is local.

Vague Triggers

Medium
Confidence
87% confidence
Finding
Relying on the bare keyword 'tts' without boundary rules is prone to false activations in ordinary conversation, logs, filenames, or quoted text. In this skill’s context, a false activation can cause arbitrary nearby text to be transmitted to the remote TTS service or converted into audio without clear user consent.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
- Output is MP3 format by default
- Requires internet connection
- Supports subtitle generation (JSON format with word-level timing)
- **Temporary File Handling**: By default, audio files are saved to the system's temporary directory (`/tmp/edge-tts-temp/` on Unix, `C:\Users\<user>\AppData\Local\Temp\edge-tts-temp\` on Windows) with unique filenames (e.g., `tts_1234567890_abc123.mp3`). Files are not automatically deleted - the calling application (Clawdbot) should handle cleanup after use. You can specify a custom output path with the `--output` option if permanent storage is needed.
- **TTS keyword filtering**: The skill automatically filters out TTS-related keywords (tts, TTS, text-to-speech) from text before conversion to avoid converting the trigger words themselves to audio
- For repeated preferences, use `config-manager.js` to set defaults
- **Default voice**: `en-US-MichelleNeural` (female, natural)
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The guide states that the module uses Microsoft Edge's online TTS service, but it does not clearly warn that supplied text is transmitted to an external network service. In a skill context, users may pass sensitive prompts, secrets, or private content to TTS, so missing privacy disclosure can cause unintended data exfiltration to a third party.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The documentation recommends executing `npx node-edge-tts` without pinning a specific version, which allows whatever package version is current in the registry at execution time to be fetched and run. In an agent or automated environment, this creates supply-chain risk because a compromised new release or dependency could execute attacker-controlled code.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This example invokes `npx node-edge-tts` directly from the registry without version pinning. If users or agents copy this command, they may execute an unexpected or malicious future package version, making this a real supply-chain exposure.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The command-line example fetches and runs `node-edge-tts` without constraining the version. In environments where agents may automatically follow documentation, this increases the chance of running unreviewed code from a package update or takeover.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
This unpinned `npx` example exposes consumers to package substitution or malicious update risk because the executed artifact is resolved at runtime. The danger is heightened for skills or bots that may operationalize example commands without human review.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
By documenting `npx node-edge-tts` without a version, the guide normalizes execution of mutable third-party code. A compromised package release could lead to arbitrary code execution on the host that runs the command.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The subtitles example again relies on unpinned `npx` execution, inheriting the same supply-chain risk as the other occurrences. Because this is a reference guide likely to be copied verbatim, the unsafe pattern is actionable and real rather than theoretical.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill sets `voice: 'en-US-MichelleNeural'` and `lang: 'en-US'` as defaults, which effectively imposes a specific language/locale choice. The file provides options to change these values later, but the initial behavior is still forced rather than explicitly user-selected or documented as a justified region-specific constraint.

Rp1

Medium
Category
MCP Rug Pull
Confidence
97% confidence
Finding
The test script invokes `npx node-edge-tts` without pinning an exact package version. `npx` may resolve and execute a different package version than the one intended, which creates a supply-chain risk if a newer compromised release is fetched during testing or CI. In this skill context, the command is directly related to TTS functionality and likely to be run by maintainers, making unexpected remote package execution more plausible.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The script sends arbitrary input text to Microsoft Edge's online TTS service via the node-edge-tts library, but it does not clearly warn users that their content leaves the local system. In a skill intended for general text conversion, users may provide sensitive prompts, credentials, personal data, or proprietary content, creating a real privacy and data-handling risk even though this is not obviously malicious.

Missing User Warnings

Low
Confidence
81% confidence
Finding
This markdown file includes CLI examples that create `output.mp3` and `output.json`, and later states these files are generated, but it does not explicitly warn users that running the commands will write files to the current workspace. For markdown files, SQP-2 applies when the description omits warnings about behaviors that could affect user data or system state.

Unpinned Dependencies

Low
Category
Supply Chain
Content
"test": "npx node-edge-tts -t \"Hello, world! This is a test of the Edge TTS service.\" -f test-output.mp3 && echo \"Test completed successfully!\""
  },
  "dependencies": {
    "node-edge-tts": "^1.2.9",
    "commander": "^11.0.0"
  },
  "author": "Clawdbot",
Confidence
90% confidence
Finding
The dependency `node-edge-tts` is specified with a caret range (`^1.2.9`), which permits automatic adoption of future minor and patch releases. This weakens build reproducibility and increases supply-chain exposure if an upstream release is malicious or introduces a vulnerable change. Because this package is central to the skill's core functionality, compromise of this dependency could affect all TTS operations.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "dependencies": {
    "node-edge-tts": "^1.2.9",
    "commander": "^11.0.0"
  },
  "author": "Clawdbot",
  "license": "MIT"
Confidence
87% confidence
Finding
The dependency `commander` is also specified with a caret range (`^11.0.0`), allowing non-deterministic upgrades. While this is a common practice, it still creates a supply-chain risk because future releases can change behavior or become compromised and then be pulled into installs automatically. In this package, `commander` is a supporting CLI dependency, so the direct impact is lower than a compromise of the main TTS library.

Static analysis

No suspicious patterns detected.