From c709e7bf731edbf85dcfb943179b77681a0d3124 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 12 Jan 2026 10:29:26 +0000 Subject: [PATCH] fix(entrypoint): quote vars to prevent password truncation and fix command loop - Fixes a vulnerability where passwords containing spaces would be truncated in `adduser`. - Fixes a bug where multiple `VPNCMD_*` commands would not be executed (only the first one ran). - Adds `tests/verify_password_fix.sh` to prevent regression. - Adds `.jules/sentinel.md` for security learnings. --- .jules/sentinel.md | 4 +++ copyables/entrypoint.sh | 16 +++++---- tests/verify_password_fix.sh | 67 ++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 .jules/sentinel.md create mode 100644 tests/verify_password_fix.sh diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 0000000..a6f9935 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2025-05-18 - Shell Variable Expansion Risks +**Vulnerability:** Unquoted variables in shell scripts caused password truncation and command execution failures. +**Learning:** `read` into an array creates a full array, but accessing `$VAR` only accesses the first element. Also unquoted variables split on spaces, breaking passwords. +**Prevention:** Always quote variable expansions (`"$VAR"`) and iterate arrays explicitly (`for i in "${ARR[@]}"`). diff --git a/copyables/entrypoint.sh b/copyables/entrypoint.sh index 0d224a0..c1f0539 100644 --- a/copyables/entrypoint.sh +++ b/copyables/entrypoint.sh @@ -142,11 +142,11 @@ if [ ! -f $CONFIG ] || [ ! -s $CONFIG ]; then for i in "${USER[@]}"; do IFS=':' read username password <<<"$i" # echo "Creating user: ${username}" - adduser $username $password + adduser "$username" "$password" done done <<<"$USERS" else - adduser $USERNAME $PASSWORD + adduser "$USERNAME" "$PASSWORD" fi echo @@ -156,14 +156,18 @@ if [ ! -f $CONFIG ] || [ ! -s $CONFIG ]; then # handle VPNCMD_* commands right before setting admin passwords if [[ $VPNCMD_SERVER ]]; then - while IFS=";" read -ra CMD; do - vpncmd_server $CMD + while IFS=";" read -ra CMDS; do + for CMD in "${CMDS[@]}"; do + vpncmd_server $CMD + done done <<<"$VPNCMD_SERVER" fi if [[ $VPNCMD_HUB ]]; then - while IFS=";" read -ra CMD; do - vpncmd_hub $CMD + while IFS=";" read -ra CMDS; do + for CMD in "${CMDS[@]}"; do + vpncmd_hub $CMD + done done <<<"$VPNCMD_HUB" fi diff --git a/tests/verify_password_fix.sh b/tests/verify_password_fix.sh new file mode 100644 index 0000000..c50d4fb --- /dev/null +++ b/tests/verify_password_fix.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +# This script verifies the fix for password truncation and command loops in entrypoint.sh logic. +# It mocks the vpncmd wrapper functions and executes the relevant logic extracted from entrypoint.sh. + +FAILures=0 + +mock_vpncmd_hub() { + echo "MOCK_HUB: $@" +} + +mock_vpncmd_server() { + echo "MOCK_SERVER: $@" +} + +adduser() { + # Mocking the adduser function from entrypoint.sh + # We want to ensure that $2 (password) is received fully + printf " $1" + mock_vpncmd_hub UserCreate "$1" /GROUP:none /REALNAME:none /NOTE:none + mock_vpncmd_hub UserPasswordSet "$1" /PASSWORD:"$2" +} + +# Test 1: Password with spaces +echo "TEST 1: Password with spaces" +USERS="alice:secret pass word" +OUTPUT=$( + while IFS=';' read -ra USER; do + for i in "${USER[@]}"; do + IFS=':' read username password <<<"$i" + adduser "$username" "$password" + done + done <<<"$USERS" +) + +echo "$OUTPUT" +if echo "$OUTPUT" | grep -q "/PASSWORD:secret pass word"; then + echo "PASS: Password correctly preserved." +else + echo "FAIL: Password truncated." + FAILures=$((FAILures+1)) +fi + +# Test 2: VPNCMD_SERVER loop +echo "TEST 2: VPNCMD_SERVER loop" +VPNCMD_SERVER="ServerCipherSet AES;LogDisable security" +vpncmd_server() { mock_vpncmd_server "$@"; } + +OUTPUT=$( + if [[ $VPNCMD_SERVER ]]; then + while IFS=";" read -ra CMDS; do + for CMD in "${CMDS[@]}"; do + vpncmd_server $CMD + done + done <<<"$VPNCMD_SERVER" + fi +) + +echo "$OUTPUT" +if echo "$OUTPUT" | grep -q "ServerCipherSet AES" && echo "$OUTPUT" | grep -q "LogDisable security"; then + echo "PASS: Both commands executed." +else + echo "FAIL: Commands missing." + FAILures=$((FAILures+1)) +fi + +exit $FAILures