Remove --exec entirely; --exec-arg is the only click-command form
A free-form shell-string --exec sitting next to the safe --exec-arg is a standing invitation for the next caller to interpolate untrusted data and reintroduce the RCE. Remove it: omarchy-notification-send --exec now errors and points at --exec-arg, and the shell drops the omarchy-exec string hint and its bash -lc execution path, leaving only the argv path. Migrate the remaining string callers (the first-run invitation hooks, wifi and welcome prompts) to --exec-arg, and update their notification mocks. Trim the verbose security comments added along the way.
This commit is contained in:
@@ -27,7 +27,7 @@ valid_url() {
|
||||
|
||||
# A printed path is only usable if it is a regular file inside DOWNLOAD_DIR.
|
||||
# Forged records (leading-dash mpv options, paths with control chars, or
|
||||
# anything that escaped the download directory) must not reach --exec.
|
||||
# anything that escaped the download directory) must not reach the click command.
|
||||
resolve_download_file() {
|
||||
local candidate=$1 file_real dir_real
|
||||
|
||||
@@ -70,9 +70,8 @@ title_from_file() {
|
||||
fi
|
||||
}
|
||||
|
||||
# The click action is passed to the shell as an argv vector (--exec-arg), so the
|
||||
# path is one literal argument and never reaches a shell. `--` still guards mpv
|
||||
# itself against parsing a leading-dash filename as an option.
|
||||
# Click action as argv (--exec-arg): the path is one literal argument, and `--`
|
||||
# keeps mpv from parsing a leading-dash filename as an option.
|
||||
playback_exec_args=(--exec-arg mpv --exec-arg -- --exec-arg)
|
||||
|
||||
# Drive the Quickshell OSD — a single overlay that updates in place (like the
|
||||
|
||||
@@ -33,10 +33,9 @@ announce() {
|
||||
omarchy-notification-wait || return 1
|
||||
|
||||
# --exec-arg rather than a libnotify action: the shell runs clicks from its own
|
||||
# omarchy-exec-argv hint and never emits ActionInvoked. Keeps the default
|
||||
# "omarchy-action" app name too, the only one shouldBypassDnd() lets through.
|
||||
# The argv form carries the crash details as literal arguments, so a hostile
|
||||
# process name can't be reparsed as a command when the toast is clicked.
|
||||
# hint and never emits ActionInvoked. Keeps the default "omarchy-action" app
|
||||
# name, the only one shouldBypassDnd() lets through. Crash details ride as
|
||||
# literal argv, so a hostile process name can't be reparsed as a command.
|
||||
omarchy-notification-send \
|
||||
--urgency critical \
|
||||
--glyph "$CRASH_GLYPH" \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# omarchy:summary=Send an Omarchy desktop notification
|
||||
# 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:args=[--exec-arg <arg>]... [--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
|
||||
@@ -12,7 +12,6 @@ glyph=
|
||||
urgency="low"
|
||||
app_name="omarchy-action"
|
||||
image=
|
||||
exec_command=
|
||||
exec_args=()
|
||||
args=()
|
||||
parsed_option_args=0
|
||||
@@ -56,23 +55,17 @@ parse_omarchy_option() {
|
||||
return 0
|
||||
;;
|
||||
--exec)
|
||||
if (($# < 2)); then
|
||||
echo "Missing value for $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
exec_command=$2
|
||||
parsed_option_args=2
|
||||
return 0
|
||||
# Removed: a free-form shell string is safe only if the caller quotes every
|
||||
# value, and its existence invites the next caller to skip that. Use --exec-arg.
|
||||
echo "--exec is no longer supported: pass each argument with --exec-arg (e.g. --exec-arg mpv --exec-arg -- --exec-arg \"\$file\")" >&2
|
||||
exit 1
|
||||
;;
|
||||
--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 "-".
|
||||
# One literal argument of the click command, taken verbatim (even a "-value").
|
||||
exec_args+=("$2")
|
||||
parsed_option_args=2
|
||||
return 0
|
||||
@@ -91,7 +84,7 @@ while (($# > 0)); do
|
||||
done
|
||||
|
||||
if (($# < 1)); then
|
||||
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]"
|
||||
echo "Usage: omarchy-notification-send [--exec-arg <arg>]... [--app-name <app-name>] [-g <glyph>] [-u <low|normal|critical>] [--image <path-or-uri>] <headline> [description] [notify-send options]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -123,22 +116,15 @@ if [[ -n $image ]]; then
|
||||
args+=("--hint=string:image-path:$image")
|
||||
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.
|
||||
#
|
||||
# --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.
|
||||
# The click command travels with the popup as an argv hint the shell runs
|
||||
# itself, so restored toasts stay clickable and senders don't block on a
|
||||
# libnotify action (which dies when the shell restarts). --exec-arg is the only
|
||||
# form: no free-form shell string to interpolate into unsafely.
|
||||
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.
|
||||
# NUL-delimit into jq so every byte survives as data: jq's own --args would eat
|
||||
# a bare "--", and a newline in an arg must 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
|
||||
|
||||
if [[ -n $description ]]; then
|
||||
|
||||
Reference in New Issue
Block a user