Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -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[@]}"`).
16 changes: 10 additions & 6 deletions copyables/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
67 changes: 67 additions & 0 deletions tests/verify_password_fix.sh
Original file line number Diff line number Diff line change
@@ -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