From c65fcd257a644e00ad61721dd393e353fc1be482 Mon Sep 17 00:00:00 2001 From: B <6723574+louisgv@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:16:26 +0000 Subject: [PATCH] fix: base64-encode commands in SSH exec to prevent injection All four SSH-based cloud drivers (aws, digitalocean, gcp, hetzner) passed the command string directly as an SSH argument, which gets interpreted by the remote shell. While current callers pass trusted E2E test code, this creates a security footgun for future changes. Fix: base64-encode the command locally and decode it on the remote side before piping to bash. The encoded string contains only safe characters [A-Za-z0-9+/=], eliminating any injection vector. Stdin is preserved for callers that pipe data into cloud_exec. Closes #2432, closes #2433, closes #2434, closes #2435 Agent: complexity-hunter --- sh/e2e/lib/clouds/aws.sh | 9 ++++++++- sh/e2e/lib/clouds/digitalocean.sh | 9 ++++++++- sh/e2e/lib/clouds/gcp.sh | 9 ++++++++- sh/e2e/lib/clouds/hetzner.sh | 9 ++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/sh/e2e/lib/clouds/aws.sh b/sh/e2e/lib/clouds/aws.sh index 335453c81..ebe882b56 100644 --- a/sh/e2e/lib/clouds/aws.sh +++ b/sh/e2e/lib/clouds/aws.sh @@ -145,9 +145,16 @@ _aws_exec() { fi fi + # Base64-encode the command to prevent shell injection when passed as an + # SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters, + # making it safe to embed in single quotes. Stdin is preserved for callers + # that pipe data into cloud_exec. + local encoded_cmd + encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n') + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ -o ConnectTimeout=10 -o LogLevel=ERROR -o BatchMode=yes \ - "ubuntu@${_AWS_INSTANCE_IP}" "${cmd}" + "ubuntu@${_AWS_INSTANCE_IP}" "printf '%s' '${encoded_cmd}' | base64 -d | bash" } # --------------------------------------------------------------------------- diff --git a/sh/e2e/lib/clouds/digitalocean.sh b/sh/e2e/lib/clouds/digitalocean.sh index fcb09b68e..9131bfec9 100644 --- a/sh/e2e/lib/clouds/digitalocean.sh +++ b/sh/e2e/lib/clouds/digitalocean.sh @@ -155,9 +155,16 @@ _digitalocean_exec() { return 1 fi + # Base64-encode the command to prevent shell injection when passed as an + # SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters, + # making it safe to embed in single quotes. Stdin is preserved for callers + # that pipe data into cloud_exec. + local encoded_cmd + encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n') + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ -o ConnectTimeout=10 -o LogLevel=ERROR -o BatchMode=yes \ - "root@${ip}" "${cmd}" + "root@${ip}" "printf '%s' '${encoded_cmd}' | base64 -d | bash" } # --------------------------------------------------------------------------- diff --git a/sh/e2e/lib/clouds/gcp.sh b/sh/e2e/lib/clouds/gcp.sh index 4294dcc4c..5871c264e 100644 --- a/sh/e2e/lib/clouds/gcp.sh +++ b/sh/e2e/lib/clouds/gcp.sh @@ -158,9 +158,16 @@ _gcp_exec() { fi fi + # Base64-encode the command to prevent shell injection when passed as an + # SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters, + # making it safe to embed in single quotes. Stdin is preserved for callers + # that pipe data into cloud_exec. + local encoded_cmd + encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n') + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \ -o ConnectTimeout=10 -o LogLevel=ERROR -o BatchMode=yes \ - "${ssh_user}@${_GCP_INSTANCE_IP}" "${cmd}" + "${ssh_user}@${_GCP_INSTANCE_IP}" "printf '%s' '${encoded_cmd}' | base64 -d | bash" } # --------------------------------------------------------------------------- diff --git a/sh/e2e/lib/clouds/hetzner.sh b/sh/e2e/lib/clouds/hetzner.sh index 80eb0a895..0ab5dc880 100644 --- a/sh/e2e/lib/clouds/hetzner.sh +++ b/sh/e2e/lib/clouds/hetzner.sh @@ -135,12 +135,19 @@ _hetzner_exec() { return 1 fi + # Base64-encode the command to prevent shell injection when passed as an + # SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters, + # making it safe to embed in single quotes. Stdin is preserved for callers + # that pipe data into cloud_exec. + local encoded_cmd + encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n') + ssh -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ -o LogLevel=ERROR \ -o BatchMode=yes \ -o ConnectTimeout=10 \ - "root@${ip}" "${cmd}" + "root@${ip}" "printf '%s' '${encoded_cmd}' | base64 -d | bash" } # ---------------------------------------------------------------------------