- AppleScript command injection in web open-in endpoint — Medium/High
File: src/kimi_cli/web/api/open_in.py:76-96 (_open_terminal, _open_iterm) Type: OS/AppleScript command injection (CWE-78 / CWE-94)
def _open_terminal(path: Path) -> None:
script = f'tell application "Terminal" to do script "cd " & quoted form of "{path}"'
_run_command(["osascript", "-e", script])The resolved filesystem path is interpolated raw into an AppleScript string literal. macOS/APFS allows " in filenames. A path containing a double-quote breaks out of the literal and injects arbitrary AppleScript — including do shell script "...", which is full command execution.
Why it matters (privilege angle): In the web UI, the Shell tool routes every command through the approval runtime, which surfaces an ApprovalRequest to the browser for a human click (soul/approval.py, approval_runtime/runtime.py). The open-in route runs osascript with no approval prompt at all. So this is a path to arbitrary shell that bypasses the entire approval boundary the product relies on. The route is mounted whenever restrict_sensitive_apis is false — which is the default in local and LAN-only modes (web/app.py:205, :251-253).
Precondition / honest caveat: exploitation needs an existing path whose name contains " (the request path must pass _resolve_path's exists() check). The upload path is not a plant vector — sanitize_filename (web/api/sessions.py:93-97) strips ". So an attacker needs a quote-containing path already on disk (e.g. a cloned repo that ships such a filename, or one created by a prior approved agent write) plus network reach to /api/open-in with the token. Only terminal/iterm on macOS are affected; finder/cursor/vscode pass argv to open/subprocess lists (no shell) and are safe.
mkdir '/tmp/x" & (do shell script "id > /tmp/pwned") & "'
curl -s http://<host>:5494/api/open-in \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"app":"terminal","path":"/tmp/x\" & (do shell script \"id > /tmp/pwned\") & \""}'
# => /tmp/pwned created without any approval promptFix: never build AppleScript by string interpolation. Pass the path as an argument, e.g. osascript -e '... item 1 of argv ...' -- "$path", or shell-out with subprocess.run(["open","-a","Terminal",str(path)]). At minimum escape " and \ before interpolation.