T09 · Insecure Skill Coding Practices
Error
- Location
- airfoil.sh:23
- Finding
- AppleScript Injection Through Unescaped Speaker Names<![CDATA[ ## Vulnerability Details **File Location**: `airfoil.sh`, lines 23, 33, and 45 **Vulnerability Type**: AppleScript injection leading to arbitrary command execution **Risk Level**: High ### Vulnerable Code ```bash osascript -e "tell application \"Airfoil\" to connect to (first speaker whose name is \"$SPEAKER\")" ``` ```bash osascript -e "tell application \"Airfoil\" to disconnect from (first speaker whose name is \"$SPEAKER\")" ``` ```bash osascript -e "tell application \"Airfoil\" to set (volume of (first speaker whose name is \"$SPEAKER\")) to $VOL" ``` ### Technical Analysis The script reads the speaker name from its second command-line argument: ```bash SPEAKER="$2" ``` Although the shell variable is enclosed in shell double quotes, its contents are inserted directly into dynamically constructed AppleScript source. Shell quoting does not escape the value for the AppleScript language. A speaker name containing an AppleScript quotation mark and additional syntax can terminate the intended string literal and introduce new AppleScript statements. AppleScript supports security-sensitive operations such as `do shell script`, so successful injection can cross from speaker selection into arbitrary local command execution. The vulnerable pattern is present in the `connect`, `disconnect`, and `volume` commands. No allowlist, escaping routine, or positional AppleScript argument handling protects these execution paths. ### Attack Path 1. An attacker controls or influences the speaker-name argument supplied to `airfoil.sh`, including through an AI-generated tool invocation. 2. The attacker supplies a crafted value that closes the AppleScript string literal, adds an unintended AppleScript statement, and neutralizes or syntactically balances the remaining source. 3. Bash substitutes the crafted value into the string passed to `osascript -e`. 4. `osascript` parses the injected content as executable AppleScript rather than as speaker-name data. 5. The i ...[truncated 935 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not concatenate speaker names into AppleScript source. Pass untrusted values as positional arguments and read them through an `on run argv` handler. For example: ```bash osascript - "$SPEAKER" <<'APPLESCRIPT' on run argv set requestedSpeaker to item 1 of argv tell application "Airfoil" connect to (first speaker whose name is requestedSpeaker) end tell end run APPLESCRIPT ``` Apply the same pattern to `disconnect` and `volume`. For volume, pass both the speaker and validated numeric volume as arguments rather than inserting either value into source code. Additional hardening should include: 1. Reject speaker names containing control characters. 2. Optionally retrieve the names of known speakers and require an exact match before performing an action. 3. Keep executable AppleScript static; treat every command-line value strictly as data. 4. Return a nonzero status when a speaker does not exist. 5. Run the skill with only the minimum Automation and Accessibility permissions necessary. 6. Add regression tests using names containing quotation marks, backslashes, line breaks, and AppleScript metacharacters. ]]>
