Back to skill

Security audit

Tts

Security checks for vulnerabilities and agentic risk

Overview

This text-to-speech skill has a coherent purpose, but its documented command usage can expose users to command execution and arbitrary file overwrite risks if user-controlled text or output paths are passed through a shell.

Install only if you are comfortable sending requested speech text to Hume AI or OpenAI and using API keys from the environment. Invoke the scripts with argument-array execution or otherwise safely escape user text, and restrict outputs to a dedicated media directory so generated audio cannot overwrite arbitrary files.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:17
Finding

Shell Command Injection Through Documented User-Text Interpolation

Content
View full analysis
/tmp/tts-command-injection-proof) ``` The resulting shell command would be equivalent to: ```bash node scripts/generate_speech.js --text "Hello $(id > /tmp/tts-command-injection-proof)" --output "output.mp3" ``` ### Attack Path 1. An attacker asks the Agent to synthesize text containing shell metacharacters or command substitution syntax. 2. The Agent follows `SKILL.md` and substitutes that text into the documented shell command. 3. The Agent executes the constructed command through a shell. 4. The shell evaluates the malicious substitution before starting Nod ...[truncated 960 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/generate_hume_speech.js:7
Finding

Arbitrary File Overwrite Through Unrestricted Output Path

Content
View full analysis
', 'Output file path (e.g., output.mp3)') ``` ```js const base64Audio = json.generations[0].audio; const buffer = Buffer.from(base64Audio, 'base64'); await fs.promises.writeFile(options.output, buffer); const absolutePath = path.resolve(options.output); console.log(`Audio saved: ${absolutePath}`); console.log(`MEDIA: ${absolutePath}`); ``` `scripts/generate_speech.js`: ```js .requiredOption('-o, --output ', 'Output file path (e.g., output.mp3)') ``` ```js const buffer = Buffer.from(await mp3.arrayBuffer()); await fs.promises.writeFile(options.output, buffer); const absolutePath = path.resolve(options.output); console.log(`Audio saved: ${absolutePath}`); console.log(`MEDIA: ${absolutePath}`); ``` ### Technical Analysis Both scripts accept an arbitrary relative or absolute path through `--output` and pass it directly to `fs.promises.writeFile`. There is no restriction to a designated media directory, no extension validation, and no check for path traversal, existing files, or symbolic links. By default, `writeFile` creates a missing file or truncates and overwrites an existing file. If the destination is a symbolic link, the write normally follows the link and modifies its target. Calling `path.resolve` after the write only formats the path for logging and provides no security validation. Exploitation requires an attacker to influence the `--output` argument, directly or through an Agent that accepts a requested destination. The generated bytes are audio data, which limits their usefulness for producing attacker-selected textual configuration content, but they can still destroy existing files or replace files whose f ...[truncated 1446 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (7)

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
91% confidence
Finding

The lockfile pins form-data to 4.0.5, which is flagged for a CRLF injection issue in multipart field names. If this skill or its dependencies construct multipart requests with attacker-controlled field names, an attacker may be able to smuggle additional headers or alter request structure, potentially causing request tampering against downstream APIs. In this TTS skill, the package is only a transitive dependency of the OpenAI client, so exploitability depends on whether multipart uploads are used with untrusted field names; that lowers immediacy but does not remove the dependency risk.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding

The skill documents use of environment secrets and outbound network access to third-party APIs, but it does not declare any explicit tool scope or permissions boundary. This creates an authorization gap where the skill may be invoked with broader capabilities than users or the platform expect, increasing the risk of secret exposure or unintended external API calls.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The activation text is broad enough to match common conversational requests such as 'audio message' or 'voice reply' without clearly restricting when the skill should run. Over-broad triggering can cause the agent to invoke this networked, secret-using skill in situations where a simpler response was intended, unnecessarily expanding exposure to external services and user data.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/generate_hume_speech.js (reported line 24)May include surrounding context.

js
try {
    console.log(`Generating speech via Hume AI for: "${options.text.substring(0, 50)}..."`);
    
    const response = await fetch('https://api.hume.ai/v0/tts', {
      method: 'POST',
      headers: {
        'X-Hume-Api-Key': apiKey,

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/generate_hume_speech.js (reported line 24)May include surrounding context.

js
try {
    console.log(`Generating speech via Hume AI for: "${options.text.substring(0, 50)}..."`);
    
    const response = await fetch('https://api.hume.ai/v0/tts', {
      method: 'POST',
      headers: {
        'X-Hume-Api-Key': apiKey,

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The dependency uses a caret range (^4.0.0), which allows automatic installation of newer minor and patch releases rather than a single vetted version. This can introduce supply-chain risk if a future upstream release contains a vulnerability, breaking change, or compromised package, though the impact here is limited because this file only declares common runtime dependencies for a TTS helper script.

Content

Scanner excerpt · scripts/package.json (reported line 7)May include surrounding context.

json
"description": "Helper script for OpenAI TTS",
  "main": "generate_speech.js",
  "dependencies": {
    "openai": "^4.0.0",
    "commander": "^11.0.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
94% confidence
Finding

The commander dependency is also specified with a caret range (^11.0.0), so installs may resolve to different package contents over time. While this is a common development practice and not inherently malicious, it weakens reproducibility and increases exposure to upstream supply-chain compromise or newly introduced vulnerabilities.

Content

Scanner excerpt · scripts/package.json (reported line 8)May include surrounding context.

json
"main": "generate_speech.js",
  "dependencies": {
    "openai": "^4.0.0",
    "commander": "^11.0.0"
  }
}

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/generate_hume_speech.js:14