CVE-2025-58178
Description
SonarQube Server and Cloud is a static analysis solution for continuous code quality and security inspection. In versions 4 to 5.3.0, a command injection vulnerability was discovered in the SonarQube Scan GitHub Action that allows untrusted input arguments to be processed without proper sanitization. Arguments sent to the action are treated as shell expressions, allowing potential execution of arbitrary commands. A fix has been released in SonarQube Scan GitHub Action 5.3.1.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
SonarSource/sonarqube-scan-actionGitHub Actions | >= 4.0.0, < 5.3.1 | 5.3.1 |
Affected products
1Patches
21a6d90ebcb0eSQSCANGHA-102 Pin actions/cache to a full-length commit SHA (#199)
1 file changed · +1 −1
action.yml+1 −1 modified@@ -33,7 +33,7 @@ runs: INPUT_SCANNERVERSION: ${{ inputs.scannerVersion }} - name: Load Sonar Scanner CLI from cache id: sonar-scanner-cli - uses: actions/cache@v4 + uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 #v4.2.4 env: # The default value is 60mins. Reaching timeout is treated the same as a cache miss. SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
016cabf33a6bSQSCANGHA-101 Add more command injection tests
4 files changed · +109 −8
action.yml+2 −4 modified@@ -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
.github/workflows/qa-main.yml+90 −3 modified@@ -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 @@ -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"}' @@ -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
scripts/run-sonar-scanner-cli.sh+11 −1 modified@@ -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' + IFS=$'\n'; args=($(echo ${INPUT_ARGS} | egrep -o '[^" '\'']+="[^"]*"|[^" '\'']+='\''[^'\'']*'\''|[^" '\'']+|"[^"]+"|'\''[^'\'']+'\''')) +fi + +for arg in "${args[@]}"; do + scanner_args+=("$arg") +done set -ux
scripts/run-sonar-scanner.sh+6 −0 added@@ -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}") +"${cmd[@]}"
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-f79p-9c5r-xg88ghsaADVISORY
- community.sonarsource.com/t/security-advisory-sonarqube-scanner-github-action/147696nvdWEB
- github.com/SonarSource/sonarqube-scan-action/commit/016cabf33a6b7edf0733e179a03ad408ad4e88banvdWEB
- github.com/SonarSource/sonarqube-scan-action/pull/200nvdWEB
- github.com/SonarSource/sonarqube-scan-action/security/advisories/GHSA-f79p-9c5r-xg88nvdWEB
- sonarsource.atlassian.net/browse/SQSCANGHA-101nvdWEB
News mentions
0No linked articles in our index yet.