Skip to content

Commit 1bddd71

Browse files
la14-1louisgv
andauthored
fix: base64-encode commands in SSH exec to prevent injection (#2448)
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 Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
1 parent 47b26de commit 1bddd71

4 files changed

Lines changed: 32 additions & 4 deletions

File tree

sh/e2e/lib/clouds/aws.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,16 @@ _aws_exec() {
145145
fi
146146
fi
147147

148+
# Base64-encode the command to prevent shell injection when passed as an
149+
# SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters,
150+
# making it safe to embed in single quotes. Stdin is preserved for callers
151+
# that pipe data into cloud_exec.
152+
local encoded_cmd
153+
encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n')
154+
148155
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
149156
-o ConnectTimeout=10 -o LogLevel=ERROR -o BatchMode=yes \
150-
"ubuntu@${_AWS_INSTANCE_IP}" "${cmd}"
157+
"ubuntu@${_AWS_INSTANCE_IP}" "printf '%s' '${encoded_cmd}' | base64 -d | bash"
151158
}
152159

153160
# ---------------------------------------------------------------------------

sh/e2e/lib/clouds/digitalocean.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,16 @@ _digitalocean_exec() {
155155
return 1
156156
fi
157157

158+
# Base64-encode the command to prevent shell injection when passed as an
159+
# SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters,
160+
# making it safe to embed in single quotes. Stdin is preserved for callers
161+
# that pipe data into cloud_exec.
162+
local encoded_cmd
163+
encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n')
164+
158165
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
159166
-o ConnectTimeout=10 -o LogLevel=ERROR -o BatchMode=yes \
160-
"root@${ip}" "${cmd}"
167+
"root@${ip}" "printf '%s' '${encoded_cmd}' | base64 -d | bash"
161168
}
162169

163170
# ---------------------------------------------------------------------------

sh/e2e/lib/clouds/gcp.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,16 @@ _gcp_exec() {
158158
fi
159159
fi
160160

161+
# Base64-encode the command to prevent shell injection when passed as an
162+
# SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters,
163+
# making it safe to embed in single quotes. Stdin is preserved for callers
164+
# that pipe data into cloud_exec.
165+
local encoded_cmd
166+
encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n')
167+
161168
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
162169
-o ConnectTimeout=10 -o LogLevel=ERROR -o BatchMode=yes \
163-
"${ssh_user}@${_GCP_INSTANCE_IP}" "${cmd}"
170+
"${ssh_user}@${_GCP_INSTANCE_IP}" "printf '%s' '${encoded_cmd}' | base64 -d | bash"
164171
}
165172

166173
# ---------------------------------------------------------------------------

sh/e2e/lib/clouds/hetzner.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,19 @@ _hetzner_exec() {
135135
return 1
136136
fi
137137

138+
# Base64-encode the command to prevent shell injection when passed as an
139+
# SSH argument. The encoded string contains only [A-Za-z0-9+/=] characters,
140+
# making it safe to embed in single quotes. Stdin is preserved for callers
141+
# that pipe data into cloud_exec.
142+
local encoded_cmd
143+
encoded_cmd=$(printf '%s' "${cmd}" | base64 | tr -d '\n')
144+
138145
ssh -o StrictHostKeyChecking=no \
139146
-o UserKnownHostsFile=/dev/null \
140147
-o LogLevel=ERROR \
141148
-o BatchMode=yes \
142149
-o ConnectTimeout=10 \
143-
"root@${ip}" "${cmd}"
150+
"root@${ip}" "printf '%s' '${encoded_cmd}' | base64 -d | bash"
144151
}
145152

146153
# ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)