T09 · Insecure Skill Coding Practices
- Location
SKILL.md:69- Finding
Shell Command Injection Through Unsafe TTS Input Interpolation
- Content
View full analysis
/dev/null | jq -r '.profiles[.defaultProfile].apiKey' 2>/dev/null)}" && \ curl -s -X POST "https://oatda.com/api/v1/llm/speech" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $OATDA_API_KEY" \ -d '{ "provider": "", "model": "", "input": "", "voice": "alloy", "response_format": "mp3", "speed": 1.0 }' \ --output speech.mp3 ``` ### Technical Analysis The Skill instructs the Agent to insert user-supplied speech text directly into a single-quoted shell argument. This does not provide safe separation between data and shell syntax. If the supplied text contains an apostrophe, it can terminate the single-quoted `curl -d` argument. Subsequent shell metacharacters may then be interpreted as commands rather than speech content. Independently of command injection, quotes, backslashes, control characters, and line breaks are not correctly JSON-escaped, which can corrupt the request body. The affected command runs after loading `OATDA_API_KEY` from the environment or `~/.oatda/credentials.json`. Consequently, successful command injection executes in a process that may have access to the OATDA credential and any other files or environment variables accessible to the Agent. Access to the OATDA-specific credential is otherwise consistent with the declared speech-generation function and does not, by itself, exceed the minimum privileges needed for API authentication. ### Attack Path 1. An attacker supplies text for speech generation containing a single quote followed by shell control syntax and an attacker-selected command. 2. The Agent substitutes that text into the `` p ...[truncated 1518 chars]- Remediation
View remediation
"$request_file" curl --fail-with-body --silent --show-error \ -X POST "https://oatda.com/api/v1/llm/speech" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $OATDA_API_KEY" \ --data-binary "@$request_file" \ --output speech.mp3 ``` 3. Keep user data in shell variables or files and never reinterpret it with `eval`, `sh -c`, or equivalent mechanisms. 4. Validate enumerated parameters such as provider, model, voice, and response format against explicit allowlists or API-discovered supported values. 5. Validate `speed` as a numeric value within the documented range before passing it through `--argjson`. 6. Use `mktemp` and a cleanup trap for temporary request files; do not use predictable shared temporary paths. 7. Use `curl --fail-with-body --silent --show-error` and verify the HTTP status and content type before treating the output as audio. 8. Select a user-approved or uniquely generated output path to avoid unintentionally overwriting an existing `speech.mp3`. 9. Continue preventing the API key from appearing in logs, command output, error messages, or generated files. 10. Add tests containing apostrophes, quotation marks, backslashes, newlines, Unicode text, and shell metacharacters to verify that all input remains inert data. ]]>
