T09 · Insecure Skill Coding Practices
- Location
scripts/transcribe.sh:73- Finding
User-Controlled Multipart Fields Permit Unintended Local File Disclosure
- Content
View full analysis
Vulnerability Details
File Location:
scripts/transcribe.sh, lines 73-82
Vulnerability Type: Unsafe use of user-controlled values in curl multipart form fields
Risk Level: Highbash curl -sS https://api.groq.com/openai/v1/audio/transcriptions \ -H "Authorization: Bearer $GROQ_API_KEY" \ -H "Accept: application/json" \ -F "file=@${in}" \ -F "model=${model}" \ -F "response_format=${response_format}" \ ${language:+-F "language=${language}"} \ ${prompt:+-F "prompt=${prompt}"} \ >"$out"Technical Analysis
The
model,language, andpromptvalues are supplied through command-line arguments and passed to curl using-F. Curl assigns special meaning to multipart values beginning with@: it treats the remainder of the value as a local filename and reads that file into the request body.Shell quoting alone does not disable curl's multipart-file interpretation. Consequently, a value such as
--prompt @/etc/passwdproduces a form field equivalent toprompt=@/etc/passwd, causing curl to read and transmit that local file.The optional
languageandpromptexpansions are also not constructed through a Bash argument array. This makes argument boundaries less robust for values containing whitespace or shell glob characters. The primary confirmed issue, however, is curl's interpretation of attacker-controlled multipart values as local file references.Attack Path
- An attacker or untrusted caller gains control over arguments passed to
transcribe.sh. - The caller supplies an existing audio file and a malicious form value, for example:
bash GROQ_API_KEY="configured-key" ./scripts/transcribe.sh audio.ogg \ --prompt '@/path/to/sensitive-file' - The script validates only the audio input and the presence of
GROQ_API_KEY; it does not reject the leading@in the prompt. - The prompt is passed to curl through
-F. - Curl interprets `@ ...[truncated 942 chars]
- An attacker or untrusted caller gains control over arguments passed to
- Remediation
View remediation
Remediation Suggestions
Use
--form-stringfor every non-file multipart field so curl always treats the supplied value as literal text. Construct curl arguments with a Bash array to preserve exact argument boundaries and avoid word splitting or pathname expansion.bash curl_args=( -sS "https://api.groq.com/openai/v1/audio/transcriptions" -H "Authorization: Bearer $GROQ_API_KEY" -H "Accept: application/json" -F "file=@${in}" --form-string "model=${model}" --form-string "response_format=${response_format}" ) if [[ -n "$language" ]]; then curl_args+=(--form-string "language=${language}") fi if [[ -n "$prompt" ]]; then curl_args+=(--form-string "prompt=${prompt}") fi curl "${curl_args[@]}" >"$out"Apply additional defense in depth:
- Validate
modelagainst an explicit allowlist of supported Groq model identifiers. - Validate
languageagainst the expected language-code syntax. - Define reasonable length limits for
prompt,model, andlanguage. - Keep
-F "file=@${in}"only for the intentionally uploaded audio file. - Add regression tests using values beginning with
@, containing spaces, and containing glob characters to verify that they remain literal form-field text.
- Validate
