Back to skill

Security audit

yaps-text-to-speech

Security checks for vulnerabilities and agentic risk

Overview

This skill is mainly a Yaps text-to-speech helper, but its bundled runtime exposes broader Yaps CLI, transcription, subtitle, meeting, account-check, and app-launch behavior that users should review before installing.

Install only if you are comfortable with this skill invoking the local Yaps app/CLI, checking account readiness, and potentially exposing broader Yaps workflows than text-to-speech if an agent is prompted to use them. Review requests before allowing it to process local audio/video files or use non-TTS Yaps commands.

Vulnerability Patterns
  • 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
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (22)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill metadata describes text-to-speech, but the code exposes transcription, subtitle generation, and meeting-processing workflows. That scope mismatch is security-relevant because it enables processing local audio/video files and creating derived artifacts outside the user-declared purpose, increasing the chance of unauthorized data access or privacy-impacting behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

The main dispatch path permits plain Yaps CLI passthrough for arbitrary arguments when the first token is not one of the adapter verbs. Even though shell injection is mitigated by spawn(..., shell:false), this still exposes whatever capabilities the installed Yaps CLI has, allowing the skill to operate well beyond the stated text-to-speech scope and potentially access sensitive local files or account-backed functions through Yaps.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 538)May include surrounding context.

js
function accountStatusUnsafeDiagnosis(appVersion) {
  return {
    code: "account_status_unsafe",
    message: `Yaps ${appVersion || "before 2.3.124"} uses an older credential-based account check, so this plugin deliberately did not run it. Update Yaps to 2.3.124 or newer; the plugin will then reuse the desktop sign-in, trial, or Yaps Pro automatically. Do not approve a Keychain prompt or create a separate plugin account.`,
  };
}

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 1024)May include surrounding context.

js
function accountStatusUnsafeDiagnosis(appVersion) {
  return {
    code: "account_status_unsafe",
    message: `Yaps ${appVersion || "before 2.3.124"} uses an older credential-based account check, so this plugin deliberately did not run it. Update Yaps to 2.3.124 or newer; the plugin will then reuse the desktop sign-in, trial, or Yaps Pro automatically. Do not approve a Keychain prompt or create a separate plugin account.`,
  };
}

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 1035)May include surrounding context.

js
function accountStatusUnsafeDiagnosis(appVersion) {
  return {
    code: "account_status_unsafe",
    message: `Yaps ${appVersion || "before 2.3.124"} uses an older credential-based account check, so this plugin deliberately did not run it. Update Yaps to 2.3.124 or newer; the plugin will then reuse the desktop sign-in, trial, or Yaps Pro automatically. Do not approve a Keychain prompt or create a separate plugin account.`,
  };
}

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 1064)May include surrounding context.

js
function accountStatusUnsafeDiagnosis(appVersion) {
  return {
    code: "account_status_unsafe",
    message: `Yaps ${appVersion || "before 2.3.124"} uses an older credential-based account check, so this plugin deliberately did not run it. Update Yaps to 2.3.124 or newer; the plugin will then reuse the desktop sign-in, trial, or Yaps Pro automatically. Do not approve a Keychain prompt or create a separate plugin account.`,
  };
}

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The code can launch the installed Yaps desktop application in the background to refresh account state. Launching local applications is a powerful side effect unrelated to the stated TTS purpose and can surprise users, trigger additional code execution in another trust boundary, and be abused for persistence-like behavior or unintended local interaction.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 1061)May include surrounding context.

js
message: "Yaps is signed in, but its trial or Yaps Pro access is not active. Open Yaps to review the available trial or Yaps Pro options; the plugin will pick up the change automatically.",
    };
  }
  if (auth.status === "credential_unavailable" || auth.diagnosticCode === "keychain_unavailable") {
    return {
      code: "account_status_unsupported",
      message: "This installed Yaps helper uses an older credential-based account check. Update Yaps and retry. Do not approve a Keychain prompt or create a separate plugin account.",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% 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.

Content

Scanner excerpt · SKILL.md (reported line 24)May include surrounding context.

md
## Boundaries

- Do not claim every language is supported or promise a cloned voice without checking the installed schema.
- Preserve existing voice settings and other installed engines.
- Generated audio must contain the supplied text completely, not just have a plausible duration.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The header comment states the adapter writes no diagnostics, credentials, settings, or host permissions, implying a minimal non-sensitive adapter surface. However, the code immediately performs session resolution, account recovery gating, and applies resolved settings paths through discovery logic, which contradicts the comment's asserted scope.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

This adapter launches an external executable with caller-influenced arguments using spawn, enabling general command invocation of the Yaps helper/CLI. While some engine invocation may be expected, exposing a generic CLI execution surface is broader than what is justified by a simple text-to-speech skill description.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 13)May include surrounding context.

js
export const MIN_SAFE_AUTH_STATUS_VERSION = "2.3.124";
const MAX_PROBE_BYTES = 64 * 1024;
const MAX_VERSION_BYTES = 4 * 1024;
const MAX_PLIST_BYTES = 64 * 1024;
const MAX_WINDOWS_SHIM_BYTES = 4 * 1024;
const RUNNING_YAPS_PROCESS_NAMES = new Set(["yaps.exe", "yaps_mcp.exe", "yaps_cli.exe"]);
// Fixed WMI filter: never interpolate a discovered path into this command.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 422)May include surrounding context.

js
export const MIN_SAFE_AUTH_STATUS_VERSION = "2.3.124";
const MAX_PROBE_BYTES = 64 * 1024;
const MAX_VERSION_BYTES = 4 * 1024;
const MAX_PLIST_BYTES = 64 * 1024;
const MAX_WINDOWS_SHIM_BYTES = 4 * 1024;
const RUNNING_YAPS_PROCESS_NAMES = new Set(["yaps.exe", "yaps_mcp.exe", "yaps_cli.exe"]);
// Fixed WMI filter: never interpolate a discovered path into this command.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The module enumerates running local processes on Windows via PowerShell/WMI to discover Yaps executables. Process enumeration exposes local environment details and exceeds what is normally necessary for a text-to-speech skill, making the capability risky in an agent context where users may not expect host introspection.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 419)May include surrounding context.

js
if (platform === "darwin") {
    const application = macApplicationForCli(cli.path, canonicalize);
    if (!application) return null;
    const plist = posix.join(application, "Contents", "Info.plist");
    try {
      const metadata = statFile(plist);
      if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 421)May include surrounding context.

js
if (platform === "darwin") {
    const application = macApplicationForCli(cli.path, canonicalize);
    if (!application) return null;
    const plist = posix.join(application, "Contents", "Info.plist");
    try {
      const metadata = statFile(plist);
      if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 427)May include surrounding context.

js
if (platform === "darwin") {
    const application = macApplicationForCli(cli.path, canonicalize);
    if (!application) return null;
    const plist = posix.join(application, "Contents", "Info.plist");
    try {
      const metadata = statFile(plist);
      if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 434)May include surrounding context.

js
if (platform === "darwin") {
    const application = macApplicationForCli(cli.path, canonicalize);
    if (!application) return null;
    const plist = posix.join(application, "Contents", "Info.plist");
    try {
      const metadata = statFile(plist);
      if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 438)May include surrounding context.

js
if (platform === "darwin") {
    const application = macApplicationForCli(cli.path, canonicalize);
    if (!application) return null;
    const plist = posix.join(application, "Contents", "Info.plist");
    try {
      const metadata = statFile(plist);
      if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · runtime/yaps-cli-discovery.mjs (reported line 442)May include surrounding context.

js
if (platform === "darwin") {
    const application = macApplicationForCli(cli.path, canonicalize);
    if (!application) return null;
    const plist = posix.join(application, "Contents", "Info.plist");
    try {
      const metadata = statFile(plist);
      if (!metadata.isFile() || metadata.size > MAX_PLIST_BYTES) return null;

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This module goes well beyond simple TTS binary discovery and performs account-state inspection, settings-path resolution, and recovery behavior tied to a locally signed-in desktop app. In an agent skill, this expands access to local state and account/session metadata that is not necessary for converting text to speech, increasing privacy and abuse risk if the skill is invoked unexpectedly or by untrusted prompts.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
runtime/run.mjs:74