Skip to content
Open
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
6 changes: 6 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Sentinel's Security Journal

## 2025-02-18 - Shell Script Variable Expansion & Read Pitfalls
**Vulnerability:** Shell script variable expansion and input reading logic flaws.
**Learning:** `read` without `-r` interprets backslashes, leading to data corruption (e.g., in passwords). Unquoted array expansion coupled with logic errors can result in incomplete execution of commands (only first command executed in a list).
**Prevention:** Always use `read -r`. Always quote variables. When iterating over lists in shell, verify loop logic and array expansion behavior.
24 changes: 14 additions & 10 deletions copyables/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ set -e

CONFIG=/var/lib/softether/vpn_server.config

if [ ! -f $CONFIG ] || [ ! -s $CONFIG ]; then
if [ ! -f "$CONFIG" ] || [ ! -s "$CONFIG" ]; then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The change to quote $CONFIG is a good practice. Unquoted variables can lead to unexpected behavior due to word splitting or globbing, especially if the path contains spaces or special characters. This improves the script's robustness and security.

# Generate a random PSK if not provided
: ${PSK:=$(cat /dev/urandom | tr -dc 'A-Za-z0-9' | fold -w 20 | head -n 1)}

Expand Down Expand Up @@ -138,15 +138,15 @@ if [ ! -f $CONFIG ] || [ ! -s $CONFIG ]; then
printf '# Creating user(s):'

if [[ $USERS ]]; then
while IFS=';' read -ra USER; do
while IFS=';' read -r -a USER; do
for i in "${USER[@]}"; do
IFS=':' read username password <<<"$i"
IFS=':' read -r 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 -r -a CMDS; do
for cmd in "${CMDS[@]}"; do
vpncmd_server $cmd

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

The original logic only executed the first command in a semicolon-separated list, silently ignoring subsequent commands, which was a critical logic flaw. However, the variable $cmd is still expanded without double quotes, which can lead to globbing and insecure word splitting. If an attacker can influence VPNCMD_SERVER (e.g., by including a * character), the shell will expand it to filenames, passing unexpected arguments to the VPN command. This undermines the PR's security hardening goals. A temporary array should be used to safely split the command string.

Suggested change
vpncmd_server $cmd
read -r -a cmd_args <<< "$cmd"
vpncmd_server "${cmd_args[@]}"

done
Comment on lines +159 to +162
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prevent globbing when dispatching VPNCMD commands.
vpncmd_* $cmd still expands globs and can mutate arguments from user-provided env vars. Re-parse into an array and pass quoted to keep splitting but block globbing.

🔧 Proposed fix
-      for cmd in "${CMDS[@]}"; do
-        vpncmd_server $cmd
-      done
+      for cmd in "${CMDS[@]}"; do
+        [[ -z "$cmd" ]] && continue
+        read -r -a CMD_PARTS <<<"$cmd"
+        vpncmd_server "${CMD_PARTS[@]}"
+      done
@@
-      for cmd in "${CMDS[@]}"; do
-        vpncmd_hub $cmd
-      done
+      for cmd in "${CMDS[@]}"; do
+        [[ -z "$cmd" ]] && continue
+        read -r -a CMD_PARTS <<<"$cmd"
+        vpncmd_hub "${CMD_PARTS[@]}"
+      done

Also applies to: 167-170

🤖 Prompt for AI Agents
In `@copyables/entrypoint.sh` around lines 159 - 162, The loop calling
vpncmd_server currently invokes it with an unquoted scalar ("vpncmd_server
$cmd") which allows pathname expansion; to fix, re-parse each command string
into an array and call vpncmd_server with the array expansion (e.g., read -r -a
ARGS <<< "$cmd" then call vpncmd_server "${ARGS[@]}") or temporarily disable
globbing with set -f around the invocation and restore it, and apply the same
change to the other occurrence mentioned (the block at the later loop around
lines 167-170); reference vpncmd_server, CMDS and cmd when making the change.

done <<<"$VPNCMD_SERVER"
fi

if [[ $VPNCMD_HUB ]]; then
while IFS=";" read -ra CMD; do
vpncmd_hub $CMD
while IFS=";" read -r -a CMDS; do
for cmd in "${CMDS[@]}"; do
vpncmd_hub $cmd

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Similar to the VPNCMD_SERVER block, ensuring all commands from VPNCMD_HUB are executed is essential for proper configuration and security. However, the $cmd variable is expanded without double quotes, which triggers globbing and insecure word splitting. This should be handled safely using an array to prevent unexpected behavior if the command contains glob characters or spaces, which could lead to silent failures of critical steps.

Suggested change
vpncmd_hub $cmd
read -r -a cmd_args <<< "$cmd"
vpncmd_hub "${cmd_args[@]}"

done
done <<<"$VPNCMD_HUB"
fi

Expand Down Expand Up @@ -191,7 +195,7 @@ else
fi

if [[ -d "/opt/scripts/" ]]; then
while read _script; do
while read -r _script; do
echo >&2 ":: executing $_script..."
bash -n "$_script" &&
bash "$_script"
Expand Down