T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/mac-contacts.py:570
- Finding
- AppleScript Injection Through Contact and Group Names<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mac-contacts.py:570-582` **Vulnerability Type**: AppleScript injection caused by unsafe source-code construction **Risk Level**: High ### Vulnerable Code ```python safe_name = args.name.replace('"', '\\"') safe_list = args.list.replace('"', '\\"') script = ( f'tell application "Contacts"\n' f' set theGroup to group "{safe_list}"\n' f' set thePeople to (every person in theGroup whose name is "{safe_name}")\n' f' repeat with p in thePeople\n' f' remove p from theGroup\n' f' end repeat\n' f' save\n' f'end tell' ) result = subprocess.run(['osascript', '-e', script], capture_output=True, text=True) ``` ### Technical Analysis The `remove_from_list` command inserts the user-controlled contact name and group name directly into dynamically generated AppleScript source code. The implementation attempts to secure these values by escaping only double quotation marks. This is not a complete AppleScript string-encoding mechanism. In particular, existing backslashes, control characters, newlines, and AppleScript syntax may affect how the generated program is parsed. Although `subprocess.run` uses an argument list and therefore avoids shell interpretation at that boundary, the input remains untrusted code at the AppleScript interpreter boundary. The correct security boundary is not the shell but the dynamically generated AppleScript program. User values must be passed as data rather than interpolated into executable source. ### Attack Path 1. An attacker creates or causes the creation of a contact or group with a specially crafted name containing AppleScript string-breaking syntax. 2. The attacker or an automated agent invokes: ```bash python3 scripts/mac-contacts.py remove_from_list "<crafted-contact>" "<crafted-group>" ``` 3. The command replaces only double quotation marks and embeds the remaining value into the AppleScript source. 4. `osascript` parses the ...[truncated 919 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Use a fixed AppleScript program and pass contact and group names through `osascript` arguments. Retrieve them from `argv` instead of concatenating them into source code. For example: ```python script = r''' on run argv set contactName to item 1 of argv set groupName to item 2 of argv tell application "Contacts" set theGroup to group groupName set thePeople to (every person in theGroup whose name is contactName) repeat with p in thePeople remove p from theGroup end repeat save end tell end run ''' result = subprocess.run( ["osascript", "-e", script, args.name, args.list], capture_output=True, text=True, check=False, ) ``` Additional hardening should include: 1. Prefer resolving the contact and group through stable identifiers rather than names. 2. Reject ambiguous contact matches before invoking Contacts.app. 3. Add regression tests for quotation marks, backslashes, newlines, Unicode separators, and AppleScript keywords. 4. Avoid printing raw interpreter errors if they may contain sensitive contact names or generated script fragments. 5. If practical, replace the AppleScript workaround with an API that supports structured parameters throughout. ]]>
