T09 · Insecure Skill Coding Practices
- Location
scripts/playlist_create.py:30- Finding
AppleScript Injection Through an Unsanitized Playlist Name
- Content
View full analysis
Vulnerability Details
File Location:
scripts/playlist_create.py, lines 30-39
Vulnerability Type: AppleScript injection leading to arbitrary command execution
Risk Level: HighVulnerable Code
python def ensure_playlist(name: str): script = f''' tell application "Music" if not (exists playlist "{name}") then make new user playlist with properties {{name:"{name}"}} end if end tell ''' r = applescript(script) return r.returncode == 0, (r.stderr or r.stdout).strip()The positional
playlistcommand-line argument is passed to this function frommain()without validation:python ok, msg = ensure_playlist(args.playlist)Technical Analysis
The playlist name is inserted directly into executable AppleScript source using a Python formatted string. No escaping or parameterization is applied before the resulting script is passed to
osascript.Because the input appears inside double-quoted AppleScript string literals, a crafted playlist name can close the string and introduce additional AppleScript statements. AppleScript supports security-sensitive operations such as
do shell script, application automation, and file manipulation. Consequently, this is not limited to altering playlist behavior: successful injection can execute arbitrary shell commands in the context of the user running the skill.Escaping only quotation marks would also be insufficient as a general design. The secure approach is to keep untrusted values entirely separate from AppleScript source and pass them through
osascriptarguments.Attack Path
- An attacker causes the skill to invoke
playlist_create.pywith an attacker-controlled playlist name. argparsestores that value inargs.playlist.main()passes the value directly toensure_playlist(args.playlist).ensure_playlist()interpolates the value into two executable AppleSc ...[truncated 1225 chars]
- An attacker causes the skill to invoke
- Remediation
View remediation
Remediation Suggestions
Do not construct AppleScript by interpolating untrusted input. Pass the playlist name as an argument and retrieve it through an AppleScript
on run argvhandler. For example:python def ensure_playlist(name: str): script = ''' on run argv set playlistName to item 1 of argv tell application "Music" if not (exists playlist playlistName) then make new user playlist with properties {name:playlistName} end if end tell end run ''' r = run(["osascript", "-e", script, name]) return r.returncode == 0, (r.stderr or r.stdout).strip()Apply the same parameterization pattern to
add_track_to_playlist(), where playlist, song, and artist values are also incorporated into generated AppleScript. Additional hardening should include:- Validate playlist names for expected length and reject control characters.
- Avoid relying on manual backslash escaping as the primary defense.
- Keep all user-controlled values outside executable AppleScript source.
- Add regression tests using names containing quotation marks, backslashes, line breaks, and AppleScript-like text.
- Return a nonzero process status when a security-sensitive playlist operation fails.
