Back to skill

Security audit

Pronunciation Coach

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its pronunciation-coaching purpose, but it sends voice recordings to an external API and documents unsafe shell commands that could run unintended commands or upload the wrong local file if inputs are not carefully constrained.

Install only if you are comfortable sending practice text and voice recordings to SenseAudio. Use a constrained runner that serializes JSON safely, passes curl arguments without a shell, validates uploaded recording paths and language codes, and stores progress only after user opt-in in a private app-state location.

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

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:41
Finding
Command Injection Through Unsafely Interpolated TTS Text<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 41-64 **Vulnerability Type**: Shell command injection through unsafe user-input interpolation **Risk Level**: High ### Vulnerable Code ```bash # Slow version (speed 0.75) curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \ -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"SenseAudio-TTS-1.0\", \"text\": \"<TEXT>\", \"stream\": false, \"voice_setting\": { \"voice_id\": \"<VOICE_ID>\", \"speed\": 0.75 }, \"audio_setting\": { \"format\": \"mp3\" } }" -o slow.json jq -r '.data.audio' slow.json | xxd -r -p > standard_slow.mp3 # Normal version (speed 1.0) curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \ -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"SenseAudio-TTS-1.0\", \"text\": \"<TEXT>\", \"stream\": false, \"voice_setting\": { \"voice_id\": \"<VOICE_ID>\", \"speed\": 1.0 }, \"audio_setting\": { \"format\": \"mp3\" } }" -o normal.json jq -r '.data.audio' normal.json | xxd -r -p > standard_normal.mp3 ``` ### Technical Analysis The practice text originates from the user and is placed inside a double-quoted shell argument. The instructions do not require JSON-safe serialization or shell-safe handling before replacing `<TEXT>`. A quotation mark in the supplied text can terminate the surrounding shell string. Shell operators, substitutions, or additional commands following that quotation mark may then be interpreted by the command shell. Ordinary text containing quotation marks or backslashes can also produce malformed JSON even when it is not intentionally malicious. The same issue applies to `<VOICE_ID>` if that value ever becomes externally controllable. This vulnerability is present when an agent or runner implements the documented command by directly replacing the placeholders and invokes it through a shell. ## ...[truncated 912 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never construct JSON by concatenating user-controlled text into a shell command. - Store the text in a shell variable and use `jq` to serialize it: ```bash payload="$( jq -n \ --arg text "$TEXT" \ --arg voice_id "$VOICE_ID" \ --argjson speed 0.75 \ '{ model: "SenseAudio-TTS-1.0", text: $text, stream: false, voice_setting: {voice_id: $voice_id, speed: $speed}, audio_setting: {format: "mp3"} }' )" curl --fail-with-body --silent --show-error \ -X POST 'https://api.senseaudio.cn/v1/t2a_v2' \ -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \ -H 'Content-Type: application/json' \ --data-binary "$payload" \ --output "$output_file" ``` - Execute commands using an argument-array API rather than constructing a command string for `sh -c`. - Keep voice identifiers on an explicit allowlist. - Check the HTTP status and validate the response schema before decoding audio. - Apply reasonable input-length limits to prevent resource exhaustion and unexpectedly large API requests. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:82
Finding
Unsafe Recording-Path Interpolation in Shell Command<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 82-89 **Vulnerability Type**: Shell command injection and unintended local-file upload **Risk Level**: High ### Vulnerable Code ```bash curl -s -X POST https://api.senseaudio.cn/v1/audio/transcriptions \ -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \ -F "file=@<USER_RECORDING>" \ -F "model=sense-asr-pro" \ -F "response_format=verbose_json" \ -F "language=<LANGUAGE_CODE>" \ -F "timestamp_granularities[]=word" \ > asr_result.json ``` ### Technical Analysis The recording path is represented by `<USER_RECORDING>` inside a shell command, but the skill does not require the placeholder to be resolved through a trusted upload-object mapping or safely passed as a single argument. If a user-controlled filename or path is inserted literally, a quotation mark can terminate the form argument and introduce shell syntax. In addition, curl's `@path` form syntax instructs curl to read and upload the named local file. If an attacker can influence the resolved path rather than merely the contents of an already validated upload, the command may upload another file readable by the agent. `<LANGUAGE_CODE>` is also interpolated into a shell argument and should be restricted to the documented allowlist. ### Attack Path 1. An attacker submits an upload with a malicious filename, or otherwise causes a user-controlled value to be used as `<USER_RECORDING>`. 2. The agent directly substitutes that value into the command. 3. For command injection, a quotation breakout causes subsequent shell syntax to be executed. 4. Alternatively, if path selection is not constrained, the attacker supplies a path to another local file. 5. Curl reads that file through `file=@...` and sends it to the external transcription endpoint. The command-injection path depends on literal shell-template substitution. The local-file-upload path depends on the attacker being able to control the resolved path. ### Impact Assess ...[truncated 409 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Resolve uploaded recordings through a trusted platform-generated file identifier rather than accepting an arbitrary path. - Canonicalize the resolved path and require it to remain inside a dedicated upload directory. - Verify that the target is a regular file and reject symbolic links, devices, FIFOs, and directory traversal. - Pass curl arguments through a process-execution API that uses an argument array and does not invoke a shell. - If a shell is unavoidable, keep the validated path in a quoted variable rather than replacing placeholders in command text: ```bash recording_path="$(realpath -- "$trusted_upload_path")" upload_root="$(realpath -- "$TRUSTED_UPLOAD_ROOT")" case "$recording_path" in "$upload_root"/*) ;; *) echo "Recording is outside the upload directory" >&2; exit 1 ;; esac test -f "$recording_path" && test ! -L "$recording_path" || exit 1 curl --fail-with-body --silent --show-error \ -X POST 'https://api.senseaudio.cn/v1/audio/transcriptions' \ -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \ --form "file=@${recording_path}" \ --form-string 'model=sense-asr-pro' \ --form-string 'response_format=verbose_json' \ --form-string "language=${LANGUAGE_CODE}" \ --form-string 'timestamp_granularities[]=word' \ --output "$asr_output" ``` - Restrict `LANGUAGE_CODE` to the documented values: `en`, `zh`, `ja`, `fr`, and `es`. - Obtain user confirmation before sending a recording to an external transcription service. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:50
Finding
Predictable Output Files Permit Symlink-Based File Overwrites<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 50-64, 89, and 151-164 **Vulnerability Type**: Unsafe predictable files and non-atomic local state storage **Risk Level**: Medium ### Vulnerable Code ```bash }" -o slow.json jq -r '.data.audio' slow.json | xxd -r -p > standard_slow.mp3 # Normal version (speed 1.0) curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \ -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"model\": \"SenseAudio-TTS-1.0\", \"text\": \"<TEXT>\", \"stream\": false, \"voice_setting\": { \"voice_id\": \"<VOICE_ID>\", \"speed\": 1.0 }, \"audio_setting\": { \"format\": \"mp3\" } }" -o normal.json jq -r '.data.audio' normal.json | xxd -r -p > standard_normal.mp3 ``` ```bash > asr_result.json ``` ```markdown Save session results to `pronunciation_progress.json` in the current directory: ```json { "sessions": [ { "date": "<ISO date>", "text": "<practice text>", "accuracy": 0.6, "errors": ["window (/ow/)", "please (final /z/)"], "phonemes_drilled": ["/ow/", "/z/"] } ] } ``` ``` ### Technical Analysis The skill uses fixed filenames in the current working directory for API responses, generated audio, transcription output, and persistent progress. Shell redirection and curl output handling normally follow existing symbolic links. If another process or workspace participant can create one of these predictable paths before the skill runs, the subsequent write can overwrite the symlink target. Repeated or concurrent sessions can also overwrite each other's files. Directly replacing `pronunciation_progress.json` without locking and atomic replacement can truncate or corrupt progress data if execution is interrupted or sessions write concurrently. The progress file also contains practice history and error information, but no restrictive permissions or retention policy is specified. ### Attack Path 1. An at ...[truncated 1001 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Create a private per-session directory with `mktemp -d` and restrictive permissions. - Place all intermediate JSON and audio files inside that directory. - Refuse to operate on symbolic links and use no-follow or exclusive-create semantics where available. - Set a restrictive file-creation mask, such as `umask 077`, before writing recordings, transcripts, or progress data. - Update persistent progress by writing to a newly created temporary file, flushing it, and atomically renaming it over the destination. - Use file locking when multiple sessions may update the same progress file. - Keep progress under a dedicated application-state directory rather than the current directory. - Define cleanup and retention behavior for generated audio, transcripts, API responses, and pronunciation history. - Validate API responses before replacing final output files so error documents are not treated as audio or session data. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (8)

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill uploads the user's voice recording to an external transcription API without a clear privacy warning or consent checkpoint. Audio recordings can contain biometric, personal, or incidental sensitive information, so transmitting them off-device without explicit notice meaningfully increases privacy and compliance risk.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Slow version (speed 0.75)
curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \
  -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Slow version (speed 0.75)
curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \
  -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Slow version (speed 0.75)
curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \
  -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Slow version (speed 0.75)
curl -s -X POST https://api.senseaudio.cn/v1/t2a_v2 \
  -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
When the user uploads their recording:

```bash
curl -s -X POST https://api.senseaudio.cn/v1/audio/transcriptions \
  -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \
  -F "file=@<USER_RECORDING>" \
  -F "model=sense-asr-pro" \
Confidence
90% confidence
Finding
This endpoint transmits the user's audio recording to an external service, which is significantly more sensitive than plain text because voice data may reveal identity, health, location context, or other incidental personal information. In this skill's context that transmission is functional, but without clear consent and privacy safeguards it is a real privacy vulnerability.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill instructs saving pronunciation text, accuracy scores, and error history to a local JSON file without informing the user or obtaining consent. This creates a privacy risk because sensitive speech practice content and performance history may persist on disk longer than the user expects and could be accessed by other local processes or users.

Description-Behavior Mismatch

Low
Confidence
83% confidence
Finding
The skill description focuses on generating model pronunciation, accepting a recording, giving feedback, and running drills. In addition, the file instructs the agent to save session results and maintain longitudinal progress data in `pronunciation_progress.json`, which is a stateful storage behavior not mentioned in the manifest description.

Static analysis

No suspicious patterns detected.