From 87d223f15a84900c08cdc8733c7ca71e9df3784d Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 27 Mar 2026 22:14:08 -0700 Subject: [PATCH] fix: shell script injection in gstack-config and telemetry (MEDIUM-04) - gstack-config: validate keys (alphanumeric+underscore only) - gstack-config: use grep -F (fixed string) instead of -E (regex) - gstack-config: escape sed special chars in values, drop newlines - gstack-telemetry-log: sanitize REPO_SLUG and BRANCH via json_safe() --- bin/gstack-config | 18 +++++++++++++++--- bin/gstack-telemetry-log | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/bin/gstack-config b/bin/gstack-config index 1147addd..821a342a 100755 --- a/bin/gstack-config +++ b/bin/gstack-config @@ -16,16 +16,28 @@ CONFIG_FILE="$STATE_DIR/config.yaml" case "${1:-}" in get) KEY="${2:?Usage: gstack-config get }" - grep -E "^${KEY}:" "$CONFIG_FILE" 2>/dev/null | tail -1 | awk '{print $2}' | tr -d '[:space:]' || true + # Validate key (alphanumeric + underscore only) + if ! printf '%s' "$KEY" | grep -qE '^[a-zA-Z0-9_]+$'; then + echo "Error: key must contain only alphanumeric characters and underscores" >&2 + exit 1 + fi + grep -F "${KEY}:" "$CONFIG_FILE" 2>/dev/null | tail -1 | awk '{print $2}' | tr -d '[:space:]' || true ;; set) KEY="${2:?Usage: gstack-config set }" VALUE="${3:?Usage: gstack-config set }" + # Validate key (alphanumeric + underscore only) + if ! printf '%s' "$KEY" | grep -qE '^[a-zA-Z0-9_]+$'; then + echo "Error: key must contain only alphanumeric characters and underscores" >&2 + exit 1 + fi mkdir -p "$STATE_DIR" - if grep -qE "^${KEY}:" "$CONFIG_FILE" 2>/dev/null; then + # Escape sed special chars in value and drop embedded newlines + ESC_VALUE="$(printf '%s' "$VALUE" | head -1 | sed 's/[&/\]/\\&/g')" + if grep -qF "${KEY}:" "$CONFIG_FILE" 2>/dev/null; then # Portable in-place edit (BSD sed uses -i '', GNU sed uses -i without arg) _tmpfile="$(mktemp "${CONFIG_FILE}.XXXXXX")" - sed "s/^${KEY}:.*/${KEY}: ${VALUE}/" "$CONFIG_FILE" > "$_tmpfile" && mv "$_tmpfile" "$CONFIG_FILE" + sed "s/^${KEY}:.*/${KEY}: ${ESC_VALUE}/" "$CONFIG_FILE" > "$_tmpfile" && mv "$_tmpfile" "$CONFIG_FILE" else echo "${KEY}: ${VALUE}" >> "$CONFIG_FILE" fi diff --git a/bin/gstack-telemetry-log b/bin/gstack-telemetry-log index da371c38..93db8207 100755 --- a/bin/gstack-telemetry-log +++ b/bin/gstack-telemetry-log @@ -158,6 +158,8 @@ OUTCOME="$(json_safe "$OUTCOME")" SESSION_ID="$(json_safe "$SESSION_ID")" SOURCE="$(json_safe "$SOURCE")" EVENT_TYPE="$(json_safe "$EVENT_TYPE")" +REPO_SLUG="$(json_safe "$REPO_SLUG")" +BRANCH="$(json_safe "$BRANCH")" # Escape null fields — sanitize ERROR_CLASS and FAILED_STEP via json_safe() ERR_FIELD="null"