fix(mcp): stop interpolating notification text into AppleScript/PowerShell - #149
Open
roshaninfordham wants to merge 2 commits into
Open
roshaninfordham wants to merge 2 commits into
roshaninfordham wants to merge 2 commits into
Conversation
…Shell DesktopNotifier.notify() built the macOS `osascript` and Windows `powershell` commands by f-string interpolating the notification title and body directly into the AppleScript/PowerShell source. A `"` or newline in that text terminates the string literal early and runs as its own statement, giving arbitrary command execution. The notifier is enabled by default (no opt-in), and the text comes from the task goal and the agent's result/explanation, which can include content read directly off the automated app's screen. Fix: keep the script text constant and pass the title/body through the subprocess environment instead, reading them back with `system attribute` (AppleScript) and `$env:` (PowerShell). Since the script source no longer varies with the input, there is no quoting/escaping question left to get wrong. Fixes google#139
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
Author
|
recheck |
roshaninfordham
added a commit
to roshaninfordham/opensource-contributions
that referenced
this pull request
Sep 22, 2026
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
roshaninfordham
added a commit
to roshaninfordham/opensource-contributions
that referenced
this pull request
Sep 22, 2026
roshaninfordham
added a commit
to roshaninfordham/opensource-contributions
that referenced
this pull request
Sep 23, 2026
…ibute
The initial version of this fix passed title/body through the subprocess
environment and read them back in AppleScript with `system attribute`.
That closes the injection (the script text is a fixed constant either
way), but `system attribute` re-decodes its value through the wrong
text encoding and corrupts non-ASCII input, including the default
title `"☕ Artemis Task {event_type}"`.
Switch to passing title/body as `on run argv` arguments after a `--`
separator instead. Argv values are passed through as literal UTF-8, so
this preserves non-ASCII text exactly while keeping the same
injection-proof property: the script source never varies with the
input. `--` prevents a title/body that happens to equal an osascript
flag (e.g. "-e") from being misparsed.
Verified against real osascript: 14 payloads (injection attempts,
edge-case flag values, non-ASCII/emoji text) all execute with
returncode 0 and empty stderr, and a byte-for-byte round-trip confirms
no corruption of legitimate non-ASCII text.
Windows branch is unchanged (env + $env:) since Windows environment
variables are natively UTF-16 and PowerShell doesn't re-decode them.
roshaninfordham
added a commit
to roshaninfordham/opensource-contributions
that referenced
this pull request
Sep 23, 2026
…in review, correct severity claim
bajnait8-dot
left a comment
There was a problem hiding this comment.
Emuchi pogram vezetője kènt mint Lilian Hercegnő mostantol a szerepjáték a manipulációk a kódsorok automatikusan a rendszer törli Karaktereket alkotokat teszi ki.Szeretet Szabadság és Barátság lett új neve Emuchinak az ikonja is kicserélödik
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Credit
This uses the same design @carfeii proposed in #139 and had already built in #140 (closed by its author). Reopening it in a CLA-cleared, tested form. Happy to close this in favor of #140 if @carfeii wants to finish their own PR instead. #58 (open, predates this issue) touches the same lines with a character-escaping approach; maintainers may prefer to pick one.
Summary
DesktopNotifier.notify()builds the macOSosascriptand Windowspowershellcommands by interpolating the notification title/body directly into the AppleScript/PowerShell source. A"or newline in that text terminates the string literal early and runs as its own statement — arbitrary command execution.Severity note: I checked every current call site of
notify()in this repo.task_runner.py/task_manager.pyalways buildmessageas a fixed literal sentence followed by"\n\n", andDesktopNotifier.notify()computesclean_body = message.split("\n\n")[0][:120]— which is always exactly that fixed sentence, never the task goal/result text that comes after it.titleis likewise always a fixed literal per call site. SoDesktopNotifier.notify()is unsafe against attacker-supplied input at the function level (any caller passing raw text directly is exploitable, which is what every PoC here does, including mine), but none of the current call sites actually route attacker content into it. This fix is real hardening — it closes the gap for any future caller, a refactor of these call sites, or a different integration — rather than a bug being exploited through today's normal task flow.Fix
Keep the AppleScript source constant and pass title/body as
on run argvarguments after a--separator, instead of interpolating them into the script text.An earlier version of this fix (matching #140's approach) passed values through the subprocess environment and read them back in AppleScript with
system attribute. That works for injection, butsystem attributere-decodes its value through the wrong text encoding and corrupts non-ASCII text — including the default title,"☕ Artemis Task {event_type}". Switched toargvinstead, which passes values through as literal UTF-8, verified with a round-trip test (see below). The Windows branch still uses the environment/$env:approach, since Windows environment variables are natively UTF-16 and PowerShell doesn't re-decode them the waysystem attributedoes.Testing
Verified live on macOS against the real
osascriptbinary:$(), backticks, CRLF, a Unicode line separator, a 5000-char string, empty string, and values equal to-e/--to check argument-parsing edge cases) through the patched code, capturing realosascriptexit codes and stderr:returncode == 0, empty stderr, no injected files, for all 14.$/backticks/newlines and non-ASCII text (café — 中文 ✓ 🔥, and the literal default title) through the fix and read them back: exact byte-for-byte match in all cases.mainand pass against the patched code.tests/unit/mcp/test_notifiers.pyfor the macOS and Windows branches.uv run pytest(full suite) onmainand this branch: same 88 pre-existing, unrelated failures on both (missing adb/credentials, Windows-only tests, stale local DB) — this branch adds 3 new passing tests and breaks nothing.uv run ruff format --check,uv run ruff check,uv run python scripts/quality_ratchet.py,uv run pyright --project pyright-core.jsonall clean on the changed files.powershell.exe.Fixes #139