T09 · Insecure Skill Coding Practices
Error
- Location
- calendar_sync.py:192
- Finding
- AppleScript Injection Through Untrusted Calendar Data<![CDATA[ ## Vulnerability Details **File Location**: `calendar_sync.py`, lines 192–224 **Vulnerability Type**: AppleScript code injection **Risk Level**: High ### Vulnerable Code ```python def register_via_applescript(docs): """macOS에서 AppleScript로 직접 캘린더에 등록""" if platform.system() != "Darwin": return False, "macOS가 아닙니다." success_count = 0 errors = [] for doc in docs: dates = doc.get("dates", {}) title = create_event_title(doc) description = create_event_description(doc).replace('"', '\\"').replace('\n', '\\n') deadline = dates.get("deadline") if not deadline: continue # AppleScript 생성 script = f''' tell application "Calendar" if not (exists calendar "문서 일정") then make new calendar with properties {{name:"문서 일정"}} end if tell calendar "문서 일정" set eventDate to date "{deadline}" make new event with properties {{ summary:"{title} - 마감", start date:eventDate, allday event:true, description:"{description}" }} end tell end tell ''' try: result = subprocess.run( ['osascript', '-e', script], capture_output=True, text=True, timeout=10 ) ``` ### Technical Analysis The `register_via_applescript` function constructs executable AppleScript by interpolating fields originating from the input JSON directly into quoted AppleScript literals. In particular: - `title` is derived from attacker-controllable `doc_type` and `title` properties. - `deadline` is read directly from `dates.deadline`. - Neither field is safely encoded before being inserted into the script. - The `deadline` used by this execution path is not passed through the existing `parse_date()` validator. - Although `description` receive ...[truncated 1906 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Do not interpolate untrusted values into executable AppleScript source. 2. Pass document values as separate `osascript` arguments and retrieve them through an `on run argv` handler. For example: ```python script = ''' on run argv set eventTitle to item 1 of argv set deadlineText to item 2 of argv set eventDescription to item 3 of argv tell application "Calendar" if not (exists calendar "문서 일정") then make new calendar with properties {name:"문서 일정"} end if tell calendar "문서 일정" set eventDate to date deadlineText make new event with properties {summary:eventTitle, start date:eventDate, allday event:true, description:eventDescription} end tell end tell end run ''' result = subprocess.run( [ "osascript", "-e", script, f"{title} - 마감", validated_deadline, description, ], capture_output=True, text=True, timeout=10, check=False, ) ``` 3. Validate `dates.deadline` with `parse_date()` before the AppleScript path and reformat the validated object using a fixed format. Reject the record if parsing fails. 4. Apply schema validation to the entire JSON input, including type checks and reasonable maximum lengths. 5. Avoid relying on manual quote replacement as a general-purpose AppleScript encoder. 6. Add regression tests containing quotes, backslashes, newlines, AppleScript delimiters, and attempted injected statements. 7. Prefer ICS generation when direct Calendar automation is unnecessary, because it avoids executing dynamically generated scripts. ]]>
