fix: shell-escape the install dir when generating the clusev CLI (R15 Codex)
A checkout path containing shell syntax ($(), quotes) could otherwise inject code into /usr/local/bin/clusev, which runs as root via 'sudo clusev update'. Render the path through printf %q into an unquoted assignment; add a test that a hostile path does not execute injected code.feat/v1-foundation
parent
8d2b7087a9
commit
5967b7b7e5
|
|
@ -6,7 +6,9 @@
|
|||
# referenced internally only — it is never printed to the operator.
|
||||
set -euo pipefail
|
||||
|
||||
CLUSEV_DIR="__CLUSEV_DIR__"
|
||||
# __CLUSEV_DIR__ is replaced by install.sh with a printf %q shell-escaped path, so this
|
||||
# unquoted assignment stays injection-safe even if the install path contains shell syntax.
|
||||
CLUSEV_DIR=__CLUSEV_DIR__
|
||||
COMPOSE_FILE="${CLUSEV_DIR}/docker-compose.prod.yml"
|
||||
|
||||
compose() { docker compose -f "$COMPOSE_FILE" "$@"; }
|
||||
|
|
|
|||
11
install.sh
11
install.sh
|
|
@ -315,11 +315,14 @@ ADMIN_MAIL="$(printf '%s\n' "$INSTALL_OUT" | sed -n 's/^CLUSEV_ADMIN_EMAIL=//p'
|
|||
# ── [9/9] Host-CLI + MOTD ────────────────────────────────────────────
|
||||
phase 9/9 "Host-CLI + MOTD installieren"
|
||||
|
||||
# clusev host command: bake the install dir into the template, drop it in PATH. Literal
|
||||
# (not sed) substitution so any path is safe; best-effort with the whole group's stderr muted
|
||||
# so a read-only /usr/local/bin never fails the installer (no stray "Permission denied").
|
||||
# clusev host command: bake the install dir into the template, drop it in PATH. The path is
|
||||
# printf %q shell-escaped before substitution so a checkout path containing shell syntax cannot
|
||||
# inject code into the generated CLI (which later runs as root via `sudo clusev update`). Literal
|
||||
# (not sed) substitution; best-effort with the whole group's stderr muted so a read-only
|
||||
# /usr/local/bin never fails the installer (no stray "Permission denied").
|
||||
cli_template="$(cat docker/clusev/clusev)"
|
||||
cli_rendered="${cli_template//__CLUSEV_DIR__/$(pwd)}"
|
||||
cli_dir="$(printf '%q' "$(pwd)")"
|
||||
cli_rendered="${cli_template//__CLUSEV_DIR__/$cli_dir}"
|
||||
if { printf '%s\n' "$cli_rendered" > /usr/local/bin/clusev && chmod 0755 /usr/local/bin/clusev; } 2>/dev/null; then
|
||||
info "Host-Befehl installiert: clusev (z. B. 'clusev ps', 'sudo clusev update')"
|
||||
else
|
||||
|
|
|
|||
|
|
@ -46,4 +46,16 @@ grep -qF "/usr/local/bin/clusev" install.sh || fail "install.sh does not install
|
|||
# 7. usage text must NOT leak the long compose filename.
|
||||
printf '%s' "$out" | grep -qF "docker-compose.prod.yml" && fail "usage leaks docker-compose.prod.yml"
|
||||
|
||||
# 8. A hostile install path (shell syntax) must not inject code into the rendered CLI.
|
||||
# install.sh escapes the path with printf %q before substituting it; mimic that here and
|
||||
# confirm running the rendered script does NOT execute the embedded command.
|
||||
evil="/tmp/x \$(touch ${TMP}/PWNED) y"
|
||||
esc="$(printf '%q' "$evil")"
|
||||
tmpl="$(cat docker/clusev/clusev)"
|
||||
printf '%s' "${tmpl//__CLUSEV_DIR__/$esc}" > "${TMP}/clusev-evil"
|
||||
chmod +x "${TMP}/clusev-evil"
|
||||
bash -n "${TMP}/clusev-evil" || fail "rendered evil-path CLI has bad syntax"
|
||||
"${TMP}/clusev-evil" help >/dev/null 2>&1 || true
|
||||
[ ! -e "${TMP}/PWNED" ] || fail "hostile install path injected code into the rendered CLI"
|
||||
|
||||
printf 'ok — clusev CLI checks passed\n'
|
||||
|
|
|
|||
Loading…
Reference in New Issue