From f1e8d946df6983d6c8ad5db0f85ecd42ee39b65a Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Wed, 11 Feb 2026 06:28:45 -0800 Subject: [PATCH] fix: secure upload_file functions against command injection in 5 clouds (#453) Replace unsafe printf '%q'-escaped unquoted variables with validated single-quoted embedding in upload_file() for fly, northflank, daytona, e2b, and koyeb. The previous pattern used unquoted $escaped_content and $escaped_path in command strings passed to bash -c or run_server, which could allow command injection via crafted filenames. The fix: - Validates remote_path rejects unsafe chars (', $, `, newlines) - Uses base64 content directly (alphanumeric + /+= is shell-safe) - Single-quotes both content and path in the command string - Uses printf '%s' instead of echo for safer output Matches the pattern already used by render, modal, and railway. Agent: security-auditor Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 --- daytona/lib/common.sh | 17 ++++++++++------- e2b/lib/common.sh | 17 ++++++++++------- fly/lib/common.sh | 19 ++++++++++++------- koyeb/lib/common.sh | 14 ++++++++------ northflank/lib/common.sh | 16 +++++++++------- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/daytona/lib/common.sh b/daytona/lib/common.sh index 03919208..63729c99 100644 --- a/daytona/lib/common.sh +++ b/daytona/lib/common.sh @@ -164,15 +164,18 @@ run_server() { upload_file() { local local_path="${1}" local remote_path="${2}" - # Upload via base64 encoding through exec (no native CLI file upload) + + # SECURITY: Validate remote_path to prevent command injection via single-quote breakout + if [[ "$remote_path" == *"'"* || "$remote_path" == *'$'* || "$remote_path" == *'`'* || "$remote_path" == *$'\n'* ]]; then + log_error "Invalid remote path (contains unsafe characters): $remote_path" + return 1 + fi + + # base64 output is safe (alphanumeric + /+=) so no injection risk local content content=$(base64 -w0 "${local_path}" 2>/dev/null || base64 "${local_path}") - # SECURITY: Properly escape paths and content - local escaped_path - escaped_path=$(printf '%q' "${remote_path}") - local escaped_content - escaped_content=$(printf '%q' "${content}") - daytona exec "${DAYTONA_SANDBOX_ID}" -- bash -c "printf '%s' ${escaped_content} | base64 -d > ${escaped_path}" + + daytona exec "${DAYTONA_SANDBOX_ID}" -- bash -c "printf '%s' '${content}' | base64 -d > '${remote_path}'" } # Daytona has true SSH support — much better than exec-only providers diff --git a/e2b/lib/common.sh b/e2b/lib/common.sh index 4d05ccbd..a884135c 100644 --- a/e2b/lib/common.sh +++ b/e2b/lib/common.sh @@ -115,15 +115,18 @@ run_server() { upload_file() { local local_path="${1}" local remote_path="${2}" - # Upload via base64 encoding through exec + + # SECURITY: Validate remote_path to prevent command injection via single-quote breakout + if [[ "$remote_path" == *"'"* || "$remote_path" == *'$'* || "$remote_path" == *'`'* || "$remote_path" == *$'\n'* ]]; then + log_error "Invalid remote path (contains unsafe characters): $remote_path" + return 1 + fi + + # base64 output is safe (alphanumeric + /+=) so no injection risk local content content=$(base64 -w0 "${local_path}" 2>/dev/null || base64 "${local_path}") - # SECURITY: Properly escape the remote path - local escaped_path - escaped_path=$(printf '%q' "${remote_path}") - local escaped_content - escaped_content=$(printf '%q' "${content}") - e2b sandbox exec "${E2B_SANDBOX_ID}" -- bash -c "echo ${escaped_content} | base64 -d > ${escaped_path}" + + e2b sandbox exec "${E2B_SANDBOX_ID}" -- bash -c "printf '%s' '${content}' | base64 -d > '${remote_path}'" } interactive_session() { diff --git a/fly/lib/common.sh b/fly/lib/common.sh index 76ed4909..011bd644 100644 --- a/fly/lib/common.sh +++ b/fly/lib/common.sh @@ -311,13 +311,18 @@ run_server() { upload_file() { local local_path="$1" local remote_path="$2" - local content=$(base64 -w0 "$local_path" 2>/dev/null || base64 "$local_path") - # SECURITY: Properly escape paths and content to prevent injection - local escaped_path - escaped_path=$(printf '%q' "$remote_path") - local escaped_content - escaped_content=$(printf '%q' "$content") - run_server "echo $escaped_content | base64 -d > $escaped_path" + + # SECURITY: Validate remote_path to prevent command injection via single-quote breakout + if [[ "$remote_path" == *"'"* || "$remote_path" == *'$'* || "$remote_path" == *'`'* || "$remote_path" == *$'\n'* ]]; then + log_error "Invalid remote path (contains unsafe characters): $remote_path" + return 1 + fi + + # base64 output is safe (alphanumeric + /+=) so no injection risk + local content + content=$(base64 -w0 "$local_path" 2>/dev/null || base64 "$local_path") + + run_server "printf '%s' '${content}' | base64 -d > '${remote_path}'" } # Start an interactive SSH session on the Fly.io machine diff --git a/koyeb/lib/common.sh b/koyeb/lib/common.sh index 7dabd634..766e0feb 100644 --- a/koyeb/lib/common.sh +++ b/koyeb/lib/common.sh @@ -222,16 +222,18 @@ upload_file() { return 1 fi + # SECURITY: Validate remote_path to prevent command injection via single-quote breakout + if [[ "$remote_path" == *"'"* || "$remote_path" == *'$'* || "$remote_path" == *'`'* || "$remote_path" == *$'\n'* ]]; then + log_error "Invalid remote path (contains unsafe characters): $remote_path" + return 1 + fi + # SECURITY: base64 -w0 produces single-line output (no newline injection) + # base64 output is safe (alphanumeric + /+=) so no injection risk local content content=$(base64 -w0 "$local_path" 2>/dev/null || base64 "$local_path") - # SECURITY: Properly escape remote_path to prevent injection - local escaped_path - escaped_path=$(printf '%q' "$remote_path") - - # base64 output is safe (alphanumeric + /+=) so no injection risk - run_server "printf '%s' '$content' | base64 -d > $escaped_path" + run_server "printf '%s' '${content}' | base64 -d > '${remote_path}'" } # Wait for cloud-init or basic system readiness diff --git a/northflank/lib/common.sh b/northflank/lib/common.sh index b21a8e03..ce8ad4d5 100644 --- a/northflank/lib/common.sh +++ b/northflank/lib/common.sh @@ -166,16 +166,18 @@ run_server() { upload_file() { local local_path="${1}" local remote_path="${2}" + + # SECURITY: Validate remote_path to prevent command injection via single-quote breakout + if [[ "$remote_path" == *"'"* || "$remote_path" == *'$'* || "$remote_path" == *'`'* || "$remote_path" == *$'\n'* ]]; then + log_error "Invalid remote path (contains unsafe characters): $remote_path" + return 1 + fi + + # base64 output is safe (alphanumeric + /+=) so no injection risk local content content=$(base64 -w0 "${local_path}" 2>/dev/null || base64 "${local_path}") - # SECURITY: Properly escape paths and content to prevent injection - local escaped_path - escaped_path=$(printf '%q' "${remote_path}") - local escaped_content - escaped_content=$(printf '%q' "${content}") - - run_server "echo ${escaped_content} | base64 -d > ${escaped_path}" + run_server "printf '%s' '${content}' | base64 -d > '${remote_path}'" } # Start an interactive shell session on the Northflank service