Run notification click actions as argv, not shell strings
The click action of a notification was a free-form shell string run through `bash -lc`, safe only when every sender shell-quoted every interpolated value perfectly. One slip is RCE: a hostile yt-dlp video title forged an output record and injected an mpv option into the click command (mehmetince.net RCE, partially addressed by #7847). Add a parameterized transport: omarchy-notification-send gains --exec-arg (repeatable), encoding a JSON argv into the omarchy-exec-argv hint. The shell runs it with Quickshell.execDetached(argv) and no shell, so data an attacker controls is only ever one argument and can never be reparsed as a command. The shell fails closed on a malformed argv hint. The legacy free-form --exec string is retained but honored only from Omarchy's own omarchy-action toasts, and deprecated. Migrate all in-repo callers (screenshot, screen recording, taildrop receive, migrate-notify, crash-watch, yt-dlp host) to --exec-arg. Update docs and tests.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Send an Omarchy desktop notification
|
||||
# omarchy:args=[--exec <command>] [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]
|
||||
# omarchy:args=[--exec-arg <arg>]... [--exec <command>] [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]
|
||||
# omarchy:examples=omarchy notification send "Reminder" "5 minutes are up" -g
|
||||
|
||||
set -euo pipefail
|
||||
@@ -13,6 +13,7 @@ urgency="low"
|
||||
app_name="omarchy-action"
|
||||
image=
|
||||
exec_command=
|
||||
exec_args=()
|
||||
args=()
|
||||
parsed_option_args=0
|
||||
|
||||
@@ -63,6 +64,19 @@ parse_omarchy_option() {
|
||||
parsed_option_args=2
|
||||
return 0
|
||||
;;
|
||||
--exec-arg)
|
||||
if (($# < 2)); then
|
||||
echo "Missing value for $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Each --exec-arg contributes one literal argument to the click command.
|
||||
# The shell runs the resulting argv vector directly (no shell), so callers
|
||||
# pass untrusted data as its own --exec-arg rather than quoting it into a
|
||||
# command string. Value is taken verbatim, even when it starts with "-".
|
||||
exec_args+=("$2")
|
||||
parsed_option_args=2
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
@@ -77,7 +91,7 @@ while (($# > 0)); do
|
||||
done
|
||||
|
||||
if (($# < 1)); then
|
||||
echo "Usage: omarchy-notification-send [--exec <command>] [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]"
|
||||
echo "Usage: omarchy-notification-send [--exec-arg <arg>]... [--exec <command>] [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -112,7 +126,18 @@ fi
|
||||
# The shell runs the click command itself, from a copy it keeps alongside the
|
||||
# on-screen popup. A libnotify action would instead keep this process blocked
|
||||
# until the click, and die unanswered whenever the shell restarts underneath it.
|
||||
if [[ -n $exec_command ]]; then
|
||||
#
|
||||
# --exec-arg builds an argv vector the shell runs directly, so a value carrying
|
||||
# untrusted data is only ever one argument and never reaches a shell. It wins
|
||||
# over the legacy free-form --exec string, which is run through `bash -lc` and
|
||||
# is only safe when the caller quoted every interpolated value itself.
|
||||
if ((${#exec_args[@]} > 0)); then
|
||||
# NUL-delimit the args into jq so every byte survives as data — jq's own
|
||||
# --args would eat a bare "--", and a title with a newline must stay one
|
||||
# element, not split the vector.
|
||||
exec_argv_json=$(printf '%s\0' "${exec_args[@]}" | jq -Rsc 'split("\u0000")[:-1]')
|
||||
args+=("--hint=string:omarchy-exec-argv:$exec_argv_json")
|
||||
elif [[ -n $exec_command ]]; then
|
||||
args+=("--hint=string:omarchy-exec:$exec_command")
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user