Skip to content

Commit 9bf3c21

Browse files
la14-1louisgvclaude
authored
fix: harden provision.sh against command injection in env_b64 and app_name (#2444)
- Validate app_name at function entry (alphanumeric, dots, hyphens, underscores only) before it's used in file paths or passed to cloud_exec - Add trap-based cleanup for the temp file used during .spawnrc fallback creation - Add security comments documenting the three-layer defense model: printf %q quoting, base64 encoding, and stdin piping (no interpolation into command strings) The core vulnerability (env_b64 interpolated into the cloud_exec command string) was already fixed in a prior commit that switched to stdin piping. This change adds defense-in-depth and documentation. Fixes #2437, #2441 Agent: code-health Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent a22fe90 commit 9bf3c21

1 file changed

Lines changed: 18 additions & 3 deletions

File tree

sh/e2e/lib/provision.sh

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ provision_agent() {
2020
local app_name="$2"
2121
local log_dir="$3"
2222

23+
# Validate app_name early — it's used in file paths and passed to cloud_exec.
24+
# Only allow alphanumeric, dots, hyphens, and underscores.
25+
if [ -z "${app_name}" ] || ! printf '%s' "${app_name}" | grep -qE '^[A-Za-z0-9._-]+$'; then
26+
log_err "Invalid app_name: must be non-empty and contain only [A-Za-z0-9._-]"
27+
return 1
28+
fi
29+
2330
local exit_file="${log_dir}/${app_name}.exit"
2431
local stdout_file="${log_dir}/${app_name}.stdout"
2532
local stderr_file="${log_dir}/${app_name}.stderr"
@@ -176,8 +183,13 @@ CLOUD_ENV
176183
# Build env lines in a temp file to avoid interpolating api_key into shell
177184
# strings directly (prevents command injection if the key contains shell
178185
# metacharacters like single quotes, backticks, or dollar signs).
186+
# printf %q shell-quotes each value; base64 encodes the result; the encoded
187+
# payload is piped via stdin to cloud_exec (never interpolated into the
188+
# remote command string). This three-layer approach (quoting + encoding +
189+
# stdin piping) ensures no user-controlled data enters shell evaluation.
179190
local env_tmp
180191
env_tmp=$(mktemp)
192+
trap 'rm -f "${env_tmp}"' RETURN
181193
{
182194
printf '%s\n' "# [spawn:env]"
183195
printf 'export IS_SANDBOX=%q\n' "1"
@@ -220,20 +232,23 @@ CLOUD_ENV
220232
local env_b64
221233
env_b64=$(base64 < "${env_tmp}" | tr -d '\n')
222234

223-
# Validate base64 output contains only safe characters (defense-in-depth)
235+
# Validate base64 output contains only safe characters (defense-in-depth).
236+
# Standard base64 only produces [A-Za-z0-9+/=]. This rejects any corruption.
224237
if ! printf '%s' "${env_b64}" | grep -qE '^[A-Za-z0-9+/=]+$'; then
225238
log_err "Invalid base64 encoding"
226-
rm -f "${env_tmp}"
227239
return 1
228240
fi
229241

242+
# SECURITY: env_b64 is piped via stdin — it is NOT interpolated into the
243+
# remote command string. The command argument to cloud_exec is a fixed
244+
# string with no variable substitution from user-controlled data.
245+
# The \$ escapes below are for remote shell variables, not local ones.
230246
if printf '%s' "${env_b64}" | cloud_exec "${app_name}" "base64 -d > ~/.spawnrc && chmod 600 ~/.spawnrc && \
231247
for _rc in ~/.bashrc ~/.profile ~/.bash_profile; do \
232248
grep -q 'source ~/.spawnrc' \"\$_rc\" 2>/dev/null || printf '%s\n' '[ -f ~/.spawnrc ] && source ~/.spawnrc' >> \"\$_rc\"; done" >/dev/null 2>&1; then
233249
log_ok "Manual .spawnrc created successfully"
234250
else
235251
log_err "Failed to create manual .spawnrc"
236252
fi
237-
rm -f "${env_tmp}"
238253
return 0
239254
}

0 commit comments

Comments
 (0)