T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:66
- Finding
- Shell Command Injection Through Unsafely Interpolated TTS Text<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 66-81 **Vulnerability Type**: Shell command injection through unsafe construction of a JSON request **Risk Level**: High ### Vulnerable Code ```bash 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>" }, "audio_setting": { "format": "mp3" } }' -o response.json # Decode hex audio to mp3 jq -r '.data.audio' response.json | xxd -r -p > output.mp3 ``` ### Technical Analysis The documented command places the `<TEXT>` and `<VOICE_ID>` placeholders inside a single-quoted shell argument. If an implementation follows these instructions by directly replacing the placeholders with user-controlled values, a single quote in the supplied text terminates the shell string. After terminating the quoted string, an attacker can introduce shell expansions, separators, redirections, or additional commands. This is not only a JSON-escaping problem: the shell interprets the injected content before `curl` receives the request. For example, text containing the following value can trigger command substitution while preserving the surrounding shell word: ```text '$(touch /tmp/injected)' ``` After direct substitution, the shell closes the original single-quoted string, evaluates `$(touch /tmp/injected)`, and then resumes the quoted argument. More harmful commands could read accessible files, modify project data, invoke other installed programs, or transmit environment variables such as `SENSEAUDIO_API_KEY`. Ordinary text containing apostrophes can also break the command or produce malformed JSON even when no malicious exploitation is attempted. ### Attack Path 1. An attacker supplies text for speech synthesis containing a single quote followed by shell synta ...[truncated 1483 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not interpolate user-controlled text or voice identifiers into shell-quoted JSON. Construct the request with a JSON-aware tool so that quotes, backslashes, newlines, and control characters are encoded safely. A hardened implementation can use `jq` to create a request file: ```bash set -euo pipefail jq -n \ --arg text "$TEXT" \ --arg voice "$VOICE_ID" \ '{ model: "SenseAudio-TTS-1.0", text: $text, stream: false, voice_setting: { voice_id: $voice }, audio_setting: { format: "mp3" } }' > request.json 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 @request.json \ -o response.json ``` Additional hardening measures should include: 1. Pass dynamic values to `jq` exclusively through `--arg`; never build shell commands with `eval`, string concatenation, or direct placeholder replacement. 2. Restrict `VOICE_ID` to the documented allowlist rather than accepting arbitrary values. 3. Verify that `.base_resp.status_code == 0` and that `.data.audio` is a valid string before decoding it. 4. Create temporary request and response files with restrictive permissions, preferably using `mktemp` and `umask 077`. 5. Quote every shell variable expansion and use fixed output directories. 6. Derive descriptive filenames through a strict safe-character allowlist rather than using raw user text as a path. 7. Run the skill with least privilege and limit its filesystem and network access to reduce the consequences of any future command-injection flaw. ]]>
