Files
kandev/apps/backend/internal/notifications
João Salavisa 410b1dd4d1 fix: prevent AppleScript injection RCE in macOS notifications (#1790)
* fix: prevent AppleScript injection RCE in macOS notifications

buildAppleScript escaped only the double-quote in notification title/body
and interpolated the result into an `osascript -e` string literal. A raw
trailing backslash defeated that escaping: `\"` became `\\"`, which
AppleScript reads as an escaped backslash plus a real closing delimiter,
so the `display notification "..."` literal terminated early and any
following text (e.g. `do shell script`) executed on the host.

Notification title/body come verbatim from untrusted external-integration
issue titles (Sentry/Linear/Jira) with no sanitization, so an attacker who
can raise an issue in a connected workspace could achieve RCE on the macOS
host when the office session reached WAITING_FOR_INPUT.

Replace string interpolation with argv passing: title/body are delivered as
`run` handler arguments (item 1/2 of argv) and never touch the AppleScript
source, so no escaping is required. Add a proof-of-concept test documenting
the legacy breakout and a regression guard asserting the fixed builder never
leaks attacker text into script fragments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: terminate osascript option parsing before notification argv

Passing untrusted title/body as trailing arguments still let a title that
looks like an osascript flag be consumed as an option: a title of "-e" would
turn the body into another script fragment, reopening the AppleScript
injection. Add a `--` option terminator before title/body so untrusted text
always lands in argv. Extend the regression tests to cover the flag-like
title vector.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test: prove single-line AppleScript payload is host RCE, not just DoS

Add a single-line (Jira/Linear, no newline) PoC alongside the multi-line
Sentry payload. A newline statement separator is only needed for a SECOND
statement; the single-line payload instead injects an expression
`& (do shell script (...))` into the display-notification body argument, so
the command executes as a side effect while the line stays one valid
statement. Both shapes are host code execution. Extend the regression guard
to prove the argv fix neutralizes both.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 10:32:55 +01:00
..
2026-01-16 23:14:09 +00:00