TL;DR: A Swift app that builds AppleScript around user-controlled paths can cross a data-code boundary and permit arbitrary command execution when escaping rules do not match the target interpreter, according to Sonar. The case reinforces that native argument passing is safer than string-built scripts, especially where untrusted content can arrive through files, archives, or repositories.
NHIMG editorial — based on content published by Sonar: AppleScript injection in OpenInTerminal and the risks of dynamic script execution
Questions worth separating out
Q: How should security teams prevent AppleScript injection in macOS utilities?
A: Use native APIs that preserve argument boundaries, and avoid building AppleScript or shell commands from user-controlled paths.
Q: Why do file paths become dangerous in command execution flows?
A: A file path becomes dangerous when software treats it as part of a command string instead of a literal parameter.
Q: What do developers get wrong about escaping input for scripts?
A: They often escape input for the first interpreter they think about, then reuse it in a second interpreter with different rules.
Practitioner guidance
- Eliminate interpreted command strings Replace any do shell script style pattern with native process execution or separately bound arguments so untrusted path data never becomes code.
- Audit secondary interpreter chains Review desktop utilities, automation scripts, and developer tools that pass Swift, Python, JavaScript, AppleScript, or shell output into another runtime.
- Test with nested and symlinked inputs Build malicious-path test cases that include nested folders, symlinks, quotes, tabs, and archive extraction flows to see where escaping breaks.
What's in the full article
Sonar's full blog post covers the technical exploit details this post intentionally leaves for the source:
- The exact AppleScript payload construction used to break out of the string context and reach arbitrary command execution
- A step-by-step explanation of how nested folders and symlinks reduce the amount of user interaction needed
- The before-and-after code path showing how structured arguments replaced string-built shell commands in the fix
- The disclosure timeline and remediation notes for the affected OpenInTerminal versions
👉 Read Sonar's analysis of the OpenInTerminal AppleScript injection flaw →
AppleScript injection in OpenInTerminal: what IAM teams should notice?
Explore further
AppleScript injection is a boundary-management failure, not a syntax mistake. The issue in OpenInTerminal is not that one quote was escaped incorrectly, but that one execution context tried to compensate for another. When applications compose code across Swift, AppleScript, and the shell, the control failure is mismatched trust boundaries, not only input filtering. Practitioners should treat any multi-interpreter chain as a code execution surface, not a convenience layer.
A question worth separating out:
Q: What should teams do when a utility shells out through another language?
A: Inventory every place the application shells out through another language, then decide whether the feature can be rewritten to use a direct process call. If it cannot, apply strict input validation, reduce user control over command parameters, and test the full path from file system input to execution output.
👉 Read our full editorial: AppleScript injection in OpenInTerminal shows why shell escaping fails