fix: prevent command injection via docker options eval
Values supplied through docker options, `--ttl-seconds`, and `-e` flowed into a Bash `eval` during build, deploy, and run, letting a low-privileged user execute arbitrary commands on the host as the dokku user. These arguments are now tokenized and passed through to the container verbatim, without shell expansion. A one-time migration repairs stored labels whose backticks were saved with a stray backslash so Traefik-style rules stay valid on the next deploy.
This commit is contained in:
@@ -105,6 +105,11 @@ teardown() {
|
||||
}
|
||||
|
||||
@test "(builder-herouish:build .env)" {
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
|
||||
@@ -146,6 +146,11 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_requirements_txt
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
|
||||
@@ -178,6 +178,11 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_requirements_txt_cnb
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
|
||||
@@ -157,6 +157,11 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_requirements_txt
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
|
||||
@@ -91,3 +91,32 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_output "false"
|
||||
}
|
||||
|
||||
@test "(common) fn-docker-args-split does not expand injected commands" {
|
||||
export DOKKU_TEST_PAYLOAD='--label x=$(id)'
|
||||
run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-docker-args-split \"\$DOKKU_TEST_PAYLOAD\" | tr '\\0' '\\n'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_line 1 'x=$(id)'
|
||||
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - value was expanded"
|
||||
|
||||
export DOKKU_TEST_PAYLOAD='--label x=`id`'
|
||||
run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-docker-args-split \"\$DOKKU_TEST_PAYLOAD\" | tr '\\0' '\\n'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_line 1 'x=`id`'
|
||||
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - value was expanded"
|
||||
|
||||
unset DOKKU_TEST_PAYLOAD
|
||||
}
|
||||
|
||||
@test "(common) fn-docker-args-split preserves quoted tokens" {
|
||||
run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-docker-args-split \"--label 'a b'\" | tr '\\0' '\\n'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_line 0 "--label"
|
||||
assert_line 1 "a b"
|
||||
}
|
||||
|
||||
@@ -285,6 +285,25 @@ teardown() {
|
||||
assert_output "/tmp:{} /var/tmp:{}"
|
||||
}
|
||||
|
||||
@test "(docker-options) deploy does not expand command substitution in option values [buildpacks]" {
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '--label=com.dokku.test=\$(id)'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run deploy_app
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
CID=$(<$DOKKU_ROOT/$TEST_APP/CONTAINER.web.1)
|
||||
run /bin/bash -c "docker inspect $CID --format '{{ index .Config.Labels \"com.dokku.test\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_output '$(id)'
|
||||
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - option value was expanded"
|
||||
}
|
||||
|
||||
@test "(docker-options) deploy with options [dockerfile]" {
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /var/tmp\""
|
||||
echo "output: $output"
|
||||
|
||||
@@ -153,3 +153,46 @@ teardown() {
|
||||
assert_success
|
||||
assert_output "2"
|
||||
}
|
||||
|
||||
@test "(run) docker-options and -e flags are not eval-injected" {
|
||||
run deploy_app
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP run '--label=com.dokku.test=safe'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku run --ttl-seconds=60 -e FOO=bar $TEST_APP env | grep -E '^FOO=bar'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku run -e 'X=\$(id)' $TEST_APP env"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
[[ "$output" == *'X=$(id)'* ]] || flunk "expected literal X=\$(id) in container env"
|
||||
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - env value was expanded"
|
||||
}
|
||||
|
||||
@test "(run) --ttl-seconds rejects non-numeric input; docker-options stores it verbatim" {
|
||||
run /bin/bash -c "dokku run --ttl-seconds '\$(id)' $TEST_APP echo hi"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_failure
|
||||
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - ttl value was expanded"
|
||||
|
||||
run /bin/bash -c "dokku docker-options:add $TEST_APP run '--label=x=\$(id)'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "dokku docker-options:report $TEST_APP --docker-options-run"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
[[ "$output" == *'x=$(id)'* ]] || flunk "expected literal x=\$(id) stored in docker options"
|
||||
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - docker option was expanded"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user