T09 · Insecure Skill Coding Practices
Error
- Location
- update_note.sh:3
- Finding
- AppleScript Injection Through Unsanitized Note Title<![CDATA[ ## Vulnerability Details **File Location**: `update_note.sh`, lines 3–10 **Vulnerability Type**: AppleScript injection leading to arbitrary command execution **Risk Level**: High ### Vulnerable Code ```bash NOTE_TITLE="$1" NEW_BODY="$2" # Создаем временный файл для NEW_BODY TMP_FILE=$(mktemp) echo "$NEW_BODY" > "$TMP_FILE" osascript <<EOF set noteTitle to "$NOTE_TITLE" ``` ### Technical Analysis The script directly interpolates the attacker-controllable `NOTE_TITLE` argument into dynamically generated AppleScript source: ```applescript set noteTitle to "$NOTE_TITLE" ``` Shell quoting used when invoking `update_note.sh` does not protect the resulting AppleScript. Because the heredoc is unquoted, the shell substitutes `NOTE_TITLE` before passing the script to `osascript`. A title containing an AppleScript string terminator, additional statements, and a comment marker can escape the intended string and become executable AppleScript. For example, a payload with the following structure can inject a shell command: ```text "; do shell script "touch /tmp/apple-notes-skill-pwned" -- ``` This causes the generated AppleScript to contain attacker-supplied executable statements. The AppleScript `do shell script` operation can then execute arbitrary local commands under the identity of the user running the skill. The temporary file path is also interpolated into the AppleScript source. Although the path is generated by `mktemp` and is not ordinarily attacker-controlled, all runtime values should be passed as data rather than embedded into executable AppleScript. ### Attack Path 1. An attacker gains influence over the note title passed as the first argument to `update_note.sh`. 2. The attacker supplies a title containing a closing quotation mark and injected AppleScript statements. 3. The unquoted heredoc expands the malicious title into the AppleScript program. 4. `osascript` parses the injected content as executable AppleScript rather than note-title ...[truncated 954 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not interpolate runtime values into AppleScript source. Pass the title and temporary-file path as arguments to `osascript`, then retrieve them through an `on run argv` handler. Use a single-quoted heredoc delimiter so the shell performs no expansion within the AppleScript. A hardened implementation can use the following pattern: ```bash #!/bin/bash set -euo pipefail if [ "$#" -ne 2 ]; then printf 'Usage: %s NOTE_TITLE NEW_BODY\n' "$0" >&2 exit 2 fi NOTE_TITLE=$1 NEW_BODY=$2 TMP_FILE=$(mktemp) trap 'rm -f -- "$TMP_FILE"' EXIT HUP INT TERM printf '%s' "$NEW_BODY" > "$TMP_FILE" osascript - "$NOTE_TITLE" "$TMP_FILE" <<'APPLESCRIPT' on run argv set noteTitle to item 1 of argv set temporaryPath to item 2 of argv set newBodyFilePath to (POSIX file temporaryPath) as alias set fileRef to missing value try set fileRef to open for access newBodyFilePath set theContent to read fileRef as «class utf8» close access fileRef set fileRef to missing value tell application "Notes" set matchingNotes to notes whose name is noteTitle if (count of matchingNotes) is not 1 then error "Expected exactly one note with the supplied title." end if set body of item 1 of matchingNotes to theContent end tell on error errorMessage number errorNumber if fileRef is not missing value then try close access fileRef end try end if error errorMessage number errorNumber end try end run APPLESCRIPT ``` Additional hardening measures include: - Validate that exactly two arguments are supplied. - Use `set -euo pipefail` to stop on failures and unset variables. - Use `printf '%s'` instead of `echo` so content beginning with options or containing escape sequences is handled consistently. - Register a cleanup trap immediately after creating the temporary ...[truncated 231 chars]
