T09 · Insecure Skill Coding Practices
- Location
scripts/say.sh:41- Finding
PowerShell Command Injection Through Unsafely Interpolated Arguments
- Content
View full analysis
/dev/null ``` ### Technical Analysis The script constructs executable PowerShell source by concatenating command-line arguments into the `PS` variable and then passes the resulting string to `powershell.exe -Command`. The attempted sanitization of `VOICE` and `TEXT` only escapes double-quote characters. These values remain inside PowerShell double-quoted strings, where PowerShell evaluates expandable expressions, including `$()` subexpressions. Consequently, attacker-controlled text containing a PowerShell subexpression can cause commands to execute while PowerShell evaluates the argument to `Speak()` or `SelectVoice()`. The `RATE` and `VOLUME` arguments present an additional and more direct injection path. They are inserted into PowerShell source without quoting, numeric validation, or range validation. Casting the value with `[int]` does not make the construction safe because an attacker can introduce PowerShell statement separators and append another statement after a syntactically valid numeric expression. The documented expected ranges—`-10..10` for rate and `0..100` for volume—are not enforced. ### Attack Path 1. An attacker gains control over text or options passed to `scripts/say.sh`, such as through an untrusted user request processed by an agent. 2. The attacker supplies either: - speech t ...[truncated 1329 chars]- Remediation
View remediation
&2 exit 1 } (( RATE >= -10 && RATE <= 10 )) || { printf 'Invalid rate: expected an integer from -10 to 10\n' >&2 exit 1 } fi if [[ -n "$VOLUME" ]]; then [[ "$VOLUME" =~ ^[0-9]+$ ]] || { printf 'Invalid volume: expected an integer from 0 to 100\n' >&2 exit 1 } (( VOLUME >= 0 && VOLUME <= 100 )) || { printf 'Invalid volume: expected an integer from 0 to 100\n' >&2 exit 1 } fi TTS_TEXT="$TEXT" \ TTS_VOICE="$VOICE" \ TTS_RATE="$RATE" \ TTS_VOLUME="$VOLUME" \ powershell.exe -NoProfile -Command ' Add-Type -AssemblyName System.Speech $s = [System.Speech.Synthesis.SpeechSynthesizer]::new() if ($env:TTS_VOICE) { $s.SelectVoice($env:TTS_VOICE) } if ($env:TTS_RATE) { $s.Rate = [int]$env:TTS_RATE } if ($env:TTS_VOLUME) { $s.Volume = [int]$env:TTS_VOLUME } $s.Speak($env:TTS_TEXT) ' ``` 6 ...[truncated 205 chars]
