Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 90 additions & 3 deletions .github/workflows/qa-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,22 @@ jobs:
- name: Run action with args
uses: ./
with:
args: -Dsonar.someArg=aValue -Dsonar.anotherArgWithSpaces="Another Value"
args: -Dsonar.someArg=aValue -Dsonar.anotherArgWithSpaces="Another Value" -Dsonar.argWithSingleQuotes='Another Value'
env:
SONAR_HOST_URL: http://not_actually_used
SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}'
- name: Assert
run: |
./test/assertFileContains ./output.properties "sonar.someArg=aValue"
./test/assertFileContains ./output.properties "sonar.anotherArgWithSpaces=Another Value"
./test/assertFileContains ./output.properties 'sonar.anotherArgWithSpaces="Another Value"'
./test/assertFileContains ./output.properties "sonar.argWithSingleQuotes='Another Value'"
argsInputInjectionTest:
name: >
'args' input with command injection will fail
strategy:
matrix:
os: [ ubuntu-latest-large, windows-latest-large, macos-latest ]
args: [ -Dsonar.someArg=aValue && echo "Injection", -Dsonar.someArg="value\"; whoami; echo \"" ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
Expand All @@ -64,7 +66,7 @@ jobs:
uses: ./
continue-on-error: true
with:
args: -Dsonar.someArg=aValue && echo "Injection"
args: ${{ matrix.args }}
env:
SONAR_HOST_URL: http://not_actually_used
SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}'
Expand All @@ -74,6 +76,91 @@ jobs:
- name: Assert the scanner was not called
run: |
./test/assertFileDoesntExist ./output.properties
backtickCommandInjectionTest:
name: >
'args' input with backticks injection does not execute command
strategy:
matrix:
os: [ ubuntu-latest-large, windows-latest-large, macos-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
uses: ./
continue-on-error: true
with:
args: >
-Dsonar.arg1="refs/heads/branch: [workflows] Bump `actions/*`" -Dsonar.arg2="test `echo Command Injection`" -Dsonar.arg3="`id`" -Dsonar.arg4="test'; `echo injection`; echo '" -Dsonar.arg5=" `whoami` " -Dsonar.arg6="test\`echo injection\`test"
env:
SONAR_HOST_URL: http://not_actually_used
SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}'
- name: Assert command in arg is not executed
run: |
./test/assertFileContains ./output.properties 'sonar.arg1="refs/heads/branch\\: \[workflows\] Bump `actions/\*`"'
./test/assertFileContains ./output.properties 'sonar.arg2="test `echo Command Injection`"'
./test/assertFileContains ./output.properties 'sonar.arg3="`id`"'
./test/assertFileContains ./output.properties "sonar.arg4=\"test'; \`echo injection\`; echo '\""
./test/assertFileContains ./output.properties 'sonar.arg5=" `whoami` "'
./test/assertFileContains ./output.properties 'sonar.arg6="test\\\\`echo injection\\\\`test"'
dollarSymbolCommandInjectionTest:
name: >
'args' input with dollar command injection does not execute command
strategy:
matrix:
os: [ ubuntu-latest-large, windows-latest-large, macos-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
uses: ./
continue-on-error: true
with:
args: -Dsonar.arg1="$(whoami)" -Dsonar.arg2="$GITHUB_TOKEN" -Dsonar.arg3="$(echo outer $(echo inner))" -Dsonar.arg4="value\$(whoami)end" -Dsonar.arg5="$(printf 'A%.0s' {1..10000})" -Dsonar.arg6='value"; $(whoami); echo "'
env:
SONAR_HOST_URL: http://not_actually_used
SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}'
- name: Assert command in arg is not executed
run: |
./test/assertFileContains ./output.properties 'sonar.arg1="$(whoami)"'
./test/assertFileContains ./output.properties 'sonar.arg2="$GITHUB_TOKEN"'
./test/assertFileContains ./output.properties 'sonar.arg3="$(echo outer $(echo inner))"'
./test/assertFileContains ./output.properties 'sonar.arg4="value\\\\$(whoami)end"'
./test/assertFileContains ./output.properties 'sonar.arg5="$(printf '\''A%.0s'\'' {1..10000})"'
./test/assertFileContains ./output.properties 'sonar.arg6='\''value"; $(whoami); echo "'\'''
otherCommandInjectionVariantsTest:
name: >
'args' input with other command injection variants does not execute command
strategy:
matrix:
os: [ ubuntu-latest-large, windows-latest-large, macos-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
uses: ./
continue-on-error: true
with:
args: -Dsonar.arg1="test | base64" -Dsonar.arg2="value; whoami" -Dsonar.arg3="value && echo test" -Dsonar.arg4="value > /tmp/output.txt" -Dsonar.arg5="< /etc/passwd" -Dsonar.arg6="" -Dsonar.arg7="../../../*" -Dsonar.arg8="*.key" -Dsonar.arg9="test\u0027\u0060whoami\u0060"
env:
SONAR_HOST_URL: http://not_actually_used
SONAR_SCANNER_JSON_PARAMS: '{"sonar.scanner.internal.dumpToFile": "./output.properties"}'
- name: Assert command in arg is not executed
run: |
./test/assertFileContains ./output.properties 'sonar.arg1="test | base64"'
./test/assertFileContains ./output.properties 'sonar.arg2="value; whoami"'
./test/assertFileContains ./output.properties 'sonar.arg3="value && echo test"'
./test/assertFileContains ./output.properties 'sonar.arg4="value > /tmp/output.txt"'
./test/assertFileContains ./output.properties 'sonar.arg5="< /etc/passwd"'
./test/assertFileContains ./output.properties 'sonar.arg6=""'
./test/assertFileContains ./output.properties 'sonar.arg7="../../../\*"'
./test/assertFileContains ./output.properties 'sonar.arg8="\*.key"'
./test/assertFileContains ./output.properties 'sonar.arg9="test\\\\u0027\\\\u0060whoami\\\\u0060"'
projectBaseDirInputTest:
name: >
'projectBaseDir' input
Expand Down
6 changes: 2 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,9 @@ runs:
run: echo "${RUNNER_TEMP}/sonar-scanner-cli-${{ inputs.scannerVersion }}-${{ runner.os }}-${{ runner.arch }}/bin" >> $GITHUB_PATH
shell: bash
- name: Run SonarScanner
run: |
args=(${{ inputs.args }})
cmd=(${GITHUB_ACTION_PATH}/scripts/run-sonar-scanner-cli.sh "${args[@]}")
"${cmd[@]}"
run: ${GITHUB_ACTION_PATH}/scripts/run-sonar-scanner.sh
shell: bash
env:
INPUT_ARGS: ${{ inputs.args }}
INPUT_PROJECTBASEDIR: ${{ inputs.projectBaseDir }}
SONAR_SCANNER_JRE: ${{ runner.temp }}/sonar-scanner-cli-${{ inputs.scannerVersion }}-${{ runner.os }}-${{ runner.arch }}/jre
2 changes: 1 addition & 1 deletion scripts/download.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ parse_arguments() {
}

verify_download_correctness() {
echo "${EXPECTED_SHA} ${TMP_ZIP_PATH}" | sha256sum -c
echo "${EXPECTED_SHA} ${TMP_ZIP_PATH}" | sha256sum -c -
check_status "Checking sha256 failed"
}

Expand Down
12 changes: 11 additions & 1 deletion scripts/run-sonar-scanner-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,17 @@ if [[ -n "${SONAR_ROOT_CERT}" ]]; then
scanner_args+=("-Dsonar.scanner.truststorePassword=$SONAR_SSL_TRUSTSTORE_PASSWORD")
fi

scanner_args+=("$@")
# split input args correctly (passed through INPUT_ARGS env var to avoid execution of injected command)
args=()
if [[ -n "${INPUT_ARGS}" ]]; then
# the regex recognizes args with values in single or double quotes (without character escaping), and args without quotes as well
# more specifically, the following patterns: -Darg="value", -Darg='value', -Darg=value, "-Darg=value" and '-Darg=value'
Comment thread
aleksandra-bozhinoska-sonarsource marked this conversation as resolved.
IFS=$'\n'; args=($(echo ${INPUT_ARGS} | egrep -o '[^" '\'']+="[^"]*"|[^" '\'']+='\''[^'\'']*'\''|[^" '\'']+|"[^"]+"|'\''[^'\'']+'\'''))
fi

for arg in "${args[@]}"; do
scanner_args+=("$arg")
done

set -ux

Expand Down
6 changes: 6 additions & 0 deletions scripts/run-sonar-scanner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail

# run the sonar scanner cli
cmd=(${GITHUB_ACTION_PATH}/scripts/run-sonar-scanner-cli.sh "${INPUT_ARGS}")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aleksandra-bozhinoska-sonarsource @antoine-vinot-sonarsource
This generates error when used in combination with additional quotes:

ie:
INPUT_ARGS: -Dsonar.projectKey=prefix_$(basename "org/repo") -Dsonar.branch.name=branch -Dsonar.scm.provider=git

It generates the following command:

sonar-scanner '-Dsonar.projectKey=prefix_$(basename' '"org/repo"' ')' -Dsonar.branch.name=branch -Dsonar.scm.provider=git

Error:
11:01:03.882 ERROR Unrecognized option: "org/repo"

"${cmd[@]}"
Loading