Back to skill

Security audit

Google Chirp 3 HD TTS Skill

Security checks for vulnerabilities and agentic risk

Overview

This text-to-speech skill is coherent in purpose, but it needs review because it auto-installs an unpinned npm dependency and can write output files outside the intended workspace.

Review before installing. Use this only in an environment where npm installation is acceptable, Google ADC credentials are scoped to the intended project, and filesystem permissions are limited. Prefer a pinned dependency with a lockfile and restrict output to a dedicated audio directory to avoid accidental overwrite of unrelated files.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:52
Finding

Unpinned Runtime Dependency Installation Creates a Supply-Chain Execution Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 52-58
Vulnerability Type: Unpinned third-party dependency installed automatically at runtime
Risk Level: Medium

Vulnerable Code

bash
### Step 3 — Auto-install dependency if missing
This installs the package **locally inside the skill folder** only.

```bash
if [ ! -d "$SKILL_DIR/node_modules/@google-cloud/text-to-speech" ]; then
    npm install @google-cloud/text-to-speech --prefix "$SKILL_DIR" --silent
fi
text

### Technical Analysis

The Skill instructs the Agent to install `@google-cloud/text-to-speech` from the public npm registry automatically when the dependency is absent. It does not specify an exact reviewed version, enforce a lockfile, verify package integrity, or disable package lifecycle scripts.

Consequently, the code executed by a first-time installation can change independently of the reviewed Skill. A compromised future release, compromised maintainer account, registry incident, or malicious transitive dependency could introduce code that executes during installation or when the package is loaded by `scripts/gtts.js`.

Installing into a local directory limits where package files are stored, but it does not sandbox npm or package lifecycle scripts. Such scripts inherit the permissions, environment, network access, and filesystem access of the Agent process.

### Attack Path

1. The Skill runs in an environment where `node_modules/@google-cloud/text-to-speech` is absent.
2. An attacker compromises a future package release, a transitive dependency, or the relevant package publishing account.
3. The Agent executes the unversioned `npm install` instruction.
4. npm resolves the currently published package graph rather than a previously audited graph.
5. Malicious installation code or imported runtime code executes with the privileges of the Agent process.
6. That code can access data and resources available to the process, p
...[truncated 520 chars]
Remediation
View remediation

Remediation Suggestions

  • Pin @google-cloud/text-to-speech to an exact, reviewed version instead of resolving the latest release.
  • Commit a generated lockfile and use npm ci so the installed dependency graph is reproducible.
  • Use npm integrity metadata and review both direct and transitive dependency changes before updating.
  • Use npm ci --ignore-scripts where dependency functionality does not require lifecycle scripts.
  • Prefer packaging audited dependencies with the Skill or performing dependency installation during a trusted build phase rather than during Skill execution.
  • Run installation and execution in a sandbox with minimal filesystem access, restricted environment variables, and outbound network access limited to required Google and npm endpoints.
  • Avoid --silent for security-sensitive installation operations so relevant warnings and failures remain visible in audit logs.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/gtts.js:79
Finding

User-Controlled Output Path Allows Arbitrary File Creation and Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/gtts.js, lines 79-109
Vulnerability Type: Unrestricted output path and unsafe file overwrite
Risk Level: Medium

Vulnerable Code

javascript
// Ensure output path is safe and explicit
const finalOutputPath = path.isAbsolute(args.out)
  ? args.out
  : path.join(DEFAULT_WORKSPACE, args.out);

// Ensure output directory exists
const outputDir = path.dirname(finalOutputPath);
if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir, { recursive: true });
}

// 2. Voice Logic
const fullVoice = args.voice.includes("Chirp3-HD")
  ? args.voice
  : `en-US-Chirp3-HD-${args.voice}`;

// 3. Input Logic — convert [pause] tags to SSML if present
const hasPauseTags = args.text.includes("[pause");
const inputData = hasPauseTags
  ? { ssml: convertPausesToSSML(args.text) }
  : { text: args.text };

const request = {
  input: inputData,
  voice: { name: fullVoice, languageCode: "en-US" },
  audioConfig: { audioEncoding: "MP3" },
};

// Generate Speech
const [response] = await client.synthesizeSpeech(request);

// Write file
fs.writeFileSync(finalOutputPath, response.audioContent, "binary");

Technical Analysis

The --out argument is accepted without path validation. Absolute paths are used directly, while relative paths are joined to the workspace without checking whether traversal components such as ../ cause the resolved path to escape that workspace.

The script also creates missing parent directories recursively and uses fs.writeFileSync without an exclusive-creation flag. Existing files are therefore overwritten by default. The comment stating that the path is “safe” is not supported by an actual containment or authorization check.

If an untrusted request can influence the filename passed by the Agent, it can select any path writable by the Skill process. The file content is an MP3 returned by Google rather than arbitr ...[truncated 1522 chars]

Remediation
View remediation

Remediation Suggestions

  • Reject absolute output paths supplied through --out.
  • Resolve output paths using path.resolve(DEFAULT_WORKSPACE, args.out) and verify that the result remains beneath the canonical workspace directory.
  • Canonicalize the workspace and relevant parent directories with fs.realpathSync where possible to prevent symbolic-link escapes.
  • Reject traversal components, null bytes, unexpected extensions, and filenames outside an explicitly allowed pattern.
  • Restrict output files to an approved extension such as .mp3.
  • Create files with an exclusive flag such as wx by default to prevent silent overwrites.
  • Require explicit trusted confirmation before overwriting an existing file.
  • Avoid recursively creating directories outside a controlled output directory.
  • Run the Skill with a minimally privileged account whose filesystem access is limited to the designated workspace.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (4)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
`gtts.js` lives in the **same folder as this SKILL.md**. Resolve that path:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill exposes code-execution-related capability through environment use and explicit shell/Node execution guidance, but it does not declare any tool scope restrictions such as allowed tools or permissions. That makes the execution boundary ambiguous and can allow an agent to invoke shell/networked behavior more broadly than intended, especially since the skill also instructs first-run dependency installation from the public npm registry.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The trigger phrases are broad enough to match ordinary conversation words like 'speak' or 'voice', which can cause unintended activation of the skill. In context, accidental activation is more dangerous because the skill may then run Node code, access credentials, perform network calls to Google APIs, and auto-install packages, turning a simple phrase collision into execution of side-effecting behavior.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The request always sets languageCode: "en-US", and the voice name is also normalized to an en-US-Chirp3-HD-* variant. This imposes a specific language/locale choice in the skill behavior without offering the user a locale option or documenting that the tool is intentionally region-specific.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.