From 1799fcd0e4569bad04abf14b4ad2935460ee69f5 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 11 Jun 2026 15:02:01 +0200 Subject: [PATCH] build-golden: harden controller-bootstrap --hostname against argv injection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate the customer.id parsed from bootstrap.json to a DNS-safe label (reject spaces/slashes/leading-dash) and pass it via a quoted array, so a malformed or hostile id can't smuggle extra docker flags (e.g. --privileged) into the controller's de-privileged `docker run`. Empty/invalid → no --hostname. Co-Authored-By: Claude Opus 4.8 (1M context) --- configs/build-golden.sh | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/configs/build-golden.sh b/configs/build-golden.sh index 7bfb696..1108943 100644 --- a/configs/build-golden.sh +++ b/configs/build-golden.sh @@ -109,8 +109,14 @@ IMAGE=$(cat /etc/felhom-controller-image 2>/dev/null || true) # ID. Portable, dependency-free parse (NO jq in the golden) — bootstrap.json has exactly one "id" key # (customer.id). Falls back to no --hostname if the parse yields nothing (fail-safe). CUSTOMER_ID=$(sed -n 's/.*"id"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$CFG" | head -1) -HOSTNAME_ARG="" -[ -n "$CUSTOMER_ID" ] && HOSTNAME_ARG="--hostname $CUSTOMER_ID" +# SECURITY: $CUSTOMER_ID is interpolated into `docker run` — reject anything that isn't a DNS-safe +# label so a malformed/hostile customer.id can't smuggle extra docker flags (e.g. --privileged, -v). +# Then pass it via a quoted array (never word-split). Empty/invalid → no --hostname (fail-safe). +case "$CUSTOMER_ID" in + ""|*[!a-zA-Z0-9._-]*|-*) CUSTOMER_ID="" ;; +esac +HOSTNAME_ARGS=() +[ -n "$CUSTOMER_ID" ] && HOSTNAME_ARGS=(--hostname "$CUSTOMER_ID") echo "[ctrl-bootstrap] deploying $IMAGE from $CFG (hostname=${CUSTOMER_ID:-})" docker rm -f felhom-controller >/dev/null 2>&1 || true # Section-G fix (base-infra slice): the controller writes app/infra compose stacks under @@ -125,7 +131,7 @@ mkdir -p /opt/docker/stacks # /etc/fstab, no rshared /mnt. Only the bootstrap config (ro), the data volume, the stacks dir # (same-path host bind), and the docker socket (app/stack management). The controller reaches the # agent's local API for disk management. -docker run -d --name felhom-controller --restart unless-stopped $HOSTNAME_ARG \ +docker run -d --name felhom-controller --restart unless-stopped "${HOSTNAME_ARGS[@]}" \ -e FELHOM_BOOTSTRAP_PATH=/etc/felhom-bootstrap/bootstrap.json \ -v /etc/felhom-bootstrap:/etc/felhom-bootstrap:ro \ -v felhom-controller-data:/opt/docker/felhom-controller \