From 90cb3e36c68741e8283d4c41fcf71c041da79dea Mon Sep 17 00:00:00 2001 From: "Calvin S." Date: Thu, 15 Oct 2026 00:03:23 -0700 Subject: [PATCH 1/4] fix(security): use random build/test VM passwords and keep them out of CI logs Addresses Mythos findings tracked under ADO 37518878: - 37518912: vhd-scanning.sh set SCAN_VM_ADMIN_PASSWORD to the deterministic "ScanVM@$CURRENT_TIME" (epoch timestamp, trivially guessable). Generate a random password instead. The "ScanVM@" prefix guarantees upper/lower/special so Azure VM password-complexity rules are still satisfied. - 37518914: run-test.sh set TEST_VM_ADMIN_PASSWORD to the deterministic "TestVM@$(date +%s)" AND echoed it verbatim to the build log; the `az vm create --admin-password` calls also ran under `set -x`, so the value was traced into the ADO log. Randomize the password, wrap the `az vm create` calls in `set +x`/`set -x`, and drop the password from the final echo (username only). No functional change to provisioning/build output beyond credential generation and log hygiene. Validated with bash -n on both scripts; the run-test ShellSpec (spec/vhdbuilder/packer/test/run_test_spec.sh) only exercises the cleanup function and retry loop, neither of which is touched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 350c2577-7031-4d0d-adc1-e99d053fc981 --- vhdbuilder/packer/test/run-test.sh | 11 +++++++++-- vhdbuilder/packer/vhd-scanning.sh | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/vhdbuilder/packer/test/run-test.sh b/vhdbuilder/packer/test/run-test.sh index 17fb803cc76..44be22f9cf5 100755 --- a/vhdbuilder/packer/test/run-test.sh +++ b/vhdbuilder/packer/test/run-test.sh @@ -24,7 +24,8 @@ fi echo "SIG image version ID from packer output: ${MANAGED_SIG_ID}" set +x -TEST_VM_ADMIN_PASSWORD="TestVM@$(date +%s)" +# use a random, non-guessable admin password (prefix guarantees upper/lower/special to satisfy Azure VM complexity rules) +TEST_VM_ADMIN_PASSWORD="TestVM@$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9')" set -x # For linux VHDs, override AZURE_LOCATION with PACKER_BUILD_LOCATION to make sure @@ -136,6 +137,8 @@ if [ "${OS_TYPE,,}" = "linux" ]; then "" \ "$TEST_VM_RESOURCE_GROUP_NAME" || exit $? else + # disable tracing so the admin password isn't emitted to the build log + set +x az vm create \ --resource-group "$TEST_VM_RESOURCE_GROUP_NAME" \ --name "$VM_NAME" \ @@ -145,8 +148,11 @@ if [ "${OS_TYPE,,}" = "linux" ]; then --nics "$TESTING_NIC_ID" \ "${TEST_VM_USER_DATA_ARGS[@]}" \ ${TARGET_COMMAND_STRING} + set -x fi else + # disable tracing so the admin password isn't emitted to the build log + set +x az vm create \ --debug \ --resource-group "$TEST_VM_RESOURCE_GROUP_NAME" \ @@ -156,9 +162,10 @@ else --admin-password "$TEST_VM_ADMIN_PASSWORD" \ --public-ip-address "" \ ${TARGET_COMMAND_STRING} + set -x fi -echo "VHD test VM username: $TEST_VM_ADMIN_USERNAME, password: $TEST_VM_ADMIN_PASSWORD" +echo "VHD test VM username: $TEST_VM_ADMIN_USERNAME" time az vm wait -g "$TEST_VM_RESOURCE_GROUP_NAME" -n "$VM_NAME" --created capture_benchmark "${SCRIPT_NAME}_create_test_vm" diff --git a/vhdbuilder/packer/vhd-scanning.sh b/vhdbuilder/packer/vhd-scanning.sh index 1223e204bc0..64902a38543 100755 --- a/vhdbuilder/packer/vhd-scanning.sh +++ b/vhdbuilder/packer/vhd-scanning.sh @@ -61,7 +61,8 @@ else fi set +x -SCAN_VM_ADMIN_PASSWORD="ScanVM@$CURRENT_TIME" +# use a random, non-guessable admin password (prefix guarantees upper/lower/special to satisfy Azure VM complexity rules) +SCAN_VM_ADMIN_PASSWORD="ScanVM@$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9')" set -x RESOURCE_GROUP_NAME="$SCAN_RESOURCE_PREFIX-$CURRENT_TIME-$RANDOM" From 5a15a215129a6bebb9720b97789b1d713b42648d Mon Sep 17 00:00:00 2001 From: "Calvin S." Date: Wed, 21 Oct 2026 20:14:21 -0700 Subject: [PATCH 2/4] Remove debug flag from VM creation command Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- vhdbuilder/packer/test/run-test.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/vhdbuilder/packer/test/run-test.sh b/vhdbuilder/packer/test/run-test.sh index 44be22f9cf5..b6ab099d7d4 100755 --- a/vhdbuilder/packer/test/run-test.sh +++ b/vhdbuilder/packer/test/run-test.sh @@ -154,7 +154,6 @@ else # disable tracing so the admin password isn't emitted to the build log set +x az vm create \ - --debug \ --resource-group "$TEST_VM_RESOURCE_GROUP_NAME" \ --name "$VM_NAME" \ --image "$MANAGED_SIG_ID" \ From bfc9bb81c8566b6c3f5862d795569d88ef0df032 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Oct 2026 03:18:48 +0000 Subject: [PATCH 3/4] test: add ShellSpec coverage for test VM credential log hygiene Co-authored-by: calvin197 <44663669+calvin197@users.noreply.github.com> --- spec/vhdbuilder/packer/test/run_test_spec.sh | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/spec/vhdbuilder/packer/test/run_test_spec.sh b/spec/vhdbuilder/packer/test/run_test_spec.sh index 4ff4b294f55..1e5386cceeb 100644 --- a/spec/vhdbuilder/packer/test/run_test_spec.sh +++ b/spec/vhdbuilder/packer/test/run_test_spec.sh @@ -103,3 +103,38 @@ Describe 'Linux content-test Run Command parameters' The output should equal "$expected_output" End End + +Describe 'Test VM credential log hygiene' + openssl() { printf 'KnownSecret+/=123\n'; } + az() { printf '%s\n' "$@" > "$AZ_ARGS"; } + + run_vm_create() ( + set -eux + VM_NAME=test-vm TEST_VM_RESOURCE_GROUP_NAME=test-rg MANAGED_SIG_ID=sig-id + TEST_VM_ADMIN_USERNAME=azureuser TESTING_NIC_ID=nic-id + TARGET_COMMAND_STRING='--size Standard_D2ds_v5' + TEST_VM_USER_DATA_ARGS=() + eval "$(sed -n '/^set +x$/,/^set -x$/p' vhdbuilder/packer/test/run-test.sh)" + eval "$(sed -n "/^$1set +x$/,/^$1set -x$/p" vhdbuilder/packer/test/run-test.sh)" + eval "$(grep '^echo "VHD test VM username:' vhdbuilder/packer/test/run-test.sh)" + ) + + Parameters + linux ' ' + windows ' ' + End + + It "passes the generated password to az vm create on $1 without logging it" + AZ_ARGS="${SHELLSPEC_WORKDIR}/az-args-$1" + When run run_vm_create "$2" + The status should be success + The contents of file "$AZ_ARGS" should include 'vm' + The contents of file "$AZ_ARGS" should include '--admin-password' + The contents of file "$AZ_ARGS" should include 'TestVM@KnownSecret123' + The contents of file "$AZ_ARGS" should not include '--debug' + The output should include 'VHD test VM username: azureuser' + The output should not include 'KnownSecret' + The error should include "+ echo 'VHD test VM username: azureuser'" + The error should not include 'KnownSecret' + End +End From 3b6a8aa84f5e0b4567d9cf68d0da4aca603f3673 Mon Sep 17 00:00:00 2001 From: "Calvin S." Date: Wed, 21 Oct 2026 21:23:33 -0700 Subject: [PATCH 4/4] fix(security): avoid masking openssl failures in VM password generation PR review caught that both password-generation pipelines (openssl rand -base64 24 | tr -dc 'A-Za-z0-9') run under 'set -e' without 'pipefail'. A pipeline's exit status is that of its last command, so a silent openssl failure would go undetected (tr succeeds on empty stdin), leaving the script to continue with a fixed, publicly-visible password ('ScanVM@' / 'TestVM@' with no random suffix) instead of aborting. Switch to openssl rand -hex 24, which needs no tr filtering (hex output is already alphanumeric), removing the pipe entirely so 'set -e' correctly aborts on an openssl failure. Verified empirically: a failing openssl now aborts the script (exit 1) instead of silently continuing. Also updates the ShellSpec test's openssl mock/assertions to match the new unfiltered-hex-output behavior (no more tr-induced character stripping). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 350c2577-7031-4d0d-adc1-e99d053fc981 --- spec/vhdbuilder/packer/test/run_test_spec.sh | 8 ++++---- vhdbuilder/packer/test/run-test.sh | 6 ++++-- vhdbuilder/packer/vhd-scanning.sh | 6 ++++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/spec/vhdbuilder/packer/test/run_test_spec.sh b/spec/vhdbuilder/packer/test/run_test_spec.sh index 1e5386cceeb..44b05cb3fa9 100644 --- a/spec/vhdbuilder/packer/test/run_test_spec.sh +++ b/spec/vhdbuilder/packer/test/run_test_spec.sh @@ -105,7 +105,7 @@ Describe 'Linux content-test Run Command parameters' End Describe 'Test VM credential log hygiene' - openssl() { printf 'KnownSecret+/=123\n'; } + openssl() { printf 'deadbeefcafebabe1234567890abcdef\n'; } az() { printf '%s\n' "$@" > "$AZ_ARGS"; } run_vm_create() ( @@ -130,11 +130,11 @@ Describe 'Test VM credential log hygiene' The status should be success The contents of file "$AZ_ARGS" should include 'vm' The contents of file "$AZ_ARGS" should include '--admin-password' - The contents of file "$AZ_ARGS" should include 'TestVM@KnownSecret123' + The contents of file "$AZ_ARGS" should include 'TestVM@deadbeefcafebabe1234567890abcdef' The contents of file "$AZ_ARGS" should not include '--debug' The output should include 'VHD test VM username: azureuser' - The output should not include 'KnownSecret' + The output should not include 'deadbeefcafebabe' The error should include "+ echo 'VHD test VM username: azureuser'" - The error should not include 'KnownSecret' + The error should not include 'deadbeefcafebabe' End End diff --git a/vhdbuilder/packer/test/run-test.sh b/vhdbuilder/packer/test/run-test.sh index b6ab099d7d4..891a7660eb5 100755 --- a/vhdbuilder/packer/test/run-test.sh +++ b/vhdbuilder/packer/test/run-test.sh @@ -24,8 +24,10 @@ fi echo "SIG image version ID from packer output: ${MANAGED_SIG_ID}" set +x -# use a random, non-guessable admin password (prefix guarantees upper/lower/special to satisfy Azure VM complexity rules) -TEST_VM_ADMIN_PASSWORD="TestVM@$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9')" +# use a random, non-guessable admin password (prefix guarantees upper/lower/special to satisfy Azure VM complexity rules). +# openssl rand -hex avoids piping through tr: under `set -e` without `pipefail`, a pipeline's exit status is +# that of its last command, so a silent openssl failure would otherwise go undetected (tr succeeds on empty input). +TEST_VM_ADMIN_PASSWORD="TestVM@$(openssl rand -hex 24)" set -x # For linux VHDs, override AZURE_LOCATION with PACKER_BUILD_LOCATION to make sure diff --git a/vhdbuilder/packer/vhd-scanning.sh b/vhdbuilder/packer/vhd-scanning.sh index 64902a38543..582f7518db8 100755 --- a/vhdbuilder/packer/vhd-scanning.sh +++ b/vhdbuilder/packer/vhd-scanning.sh @@ -61,8 +61,10 @@ else fi set +x -# use a random, non-guessable admin password (prefix guarantees upper/lower/special to satisfy Azure VM complexity rules) -SCAN_VM_ADMIN_PASSWORD="ScanVM@$(openssl rand -base64 24 | tr -dc 'A-Za-z0-9')" +# use a random, non-guessable admin password (prefix guarantees upper/lower/special to satisfy Azure VM complexity rules). +# openssl rand -hex avoids piping through tr: under `set -e` without `pipefail`, a pipeline's exit status is +# that of its last command, so a silent openssl failure would otherwise go undetected (tr succeeds on empty input). +SCAN_VM_ADMIN_PASSWORD="ScanVM@$(openssl rand -hex 24)" set -x RESOURCE_GROUP_NAME="$SCAN_RESOURCE_PREFIX-$CURRENT_TIME-$RANDOM"