From 60eddfee3f2b02d85c93f410cce604826c07b94b Mon Sep 17 00:00:00 2001 From: Jonathan Santilli <1774227+jonathansantilli@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:28:59 +0000 Subject: [PATCH 1/4] fix: prevent shell injection via eval and pin actions to SHAs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Security fix for command injection vulnerability (CWE-78) in both action.yml and review/action.yml. Changes: - Remove eval — replace with bash array execution for safe invocation - Move all ${{ inputs.* }} from run: blocks to env: blocks to prevent shell injection via attacker-controlled values - Remove debug echo that printed API tokens and github-token to logs - Replace bash -l {0} (login shell) with bash (standard shell) - Quote all variable expansions to prevent word splitting - Pin all action references to immutable commit SHAs: - actions/setup-node v3.6.0 -> v4.4.0 (SHA pinned) - actions/checkout v3 -> v4.3.1 (SHA pinned) - actions/upload-artifact v4 -> v4.6.2 (SHA pinned) - actions/download-artifact v4 -> v8.0.1 (SHA pinned) - Sibz/github-status-action v1 (SHA pinned) The action interface (inputs/outputs) is unchanged — this fix is transparent to consumers. Ref: E-1815 --- action.yml | 61 ++++++++++++++++++++++++++++------------------- review/action.yml | 55 +++++++++++++++++++++++++----------------- 2 files changed, 69 insertions(+), 47 deletions(-) diff --git a/action.yml b/action.yml index 2a23d85..9ed1d0b 100644 --- a/action.yml +++ b/action.yml @@ -33,7 +33,7 @@ outputs: runs: using: "composite" steps: - - uses: actions/setup-node@v3.6.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 18 - id: run-npx-mobb-dev @@ -42,55 +42,66 @@ runs: REPO=${REPO%".git"} BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} - MobbExecString="npx --yes mobbdev@latest analyze --ci -r $REPO --ref $BRANCH --api-key ${{ inputs.api-key }} -f ${{ inputs.report-file }}" - + MOBB_ARGS=( + npx --yes mobbdev@latest analyze --ci + -r "$REPO" + --ref "$BRANCH" + --api-key "$MOBB_API_KEY" + -f "$REPORT_FILE" + ) + # Check if mobb-project-name exists and append it - if [ -n "${{ inputs.mobb-project-name }}" ]; then - echo "mobb-project-name specified: ${{ inputs.mobb-project-name }}" - MobbExecString+=" --mobb-project-name \"${{ inputs.mobb-project-name }}\"" + if [ -n "$MOBB_PROJECT_NAME" ]; then + echo "mobb-project-name specified: $MOBB_PROJECT_NAME" + MOBB_ARGS+=(--mobb-project-name "$MOBB_PROJECT_NAME") fi # Check if organization-id exists and append it - if [ -n "${{ inputs.organization-id }}" ]; then - echo "organization-id specified: ${{ inputs.organization-id }}" - MobbExecString+=" --organization-id \"${{ inputs.organization-id }}\"" + if [ -n "$MOBB_ORG_ID" ]; then + echo "organization-id specified: $MOBB_ORG_ID" + MOBB_ARGS+=(--organization-id "$MOBB_ORG_ID") fi # Check if auto-pr flag is set append it - if [ "${{ inputs.auto-pr }}" == "true" ]; then + if [ "$AUTO_PR" == "true" ]; then echo "Auto-PR flag is set" - MobbExecString+=" --auto-pr" + MOBB_ARGS+=(--auto-pr) fi # Check if commit-directly flag is set append it to the Mobb CLI command - if [ "${{ inputs.commit-directly }}" == "true" ]; then + if [ "$COMMIT_DIRECTLY" == "true" ]; then echo "Commit Directly flag is set" - MobbExecString+=" --commit-directly" + MOBB_ARGS+=(--commit-directly) # Check if the action is running in the context of a pull request - if [ -n "${{ github.event.pull_request.number }}" ]; then - PR_ID="${{ github.event.pull_request.number }}" + PR_ID="${{ github.event.pull_request.number }}" + if [ -n "$PR_ID" ]; then echo "Pull Request ID detected: $PR_ID" - MobbExecString+=" --pr-id $PR_ID" + MOBB_ARGS+=(--pr-id "$PR_ID") else echo "No Pull Request detected. Skipping --pr-id flag." fi fi - # Output the final command string for debugging and execute it - echo "Mobb Command: $MobbExecString" - OUT=$(eval $MobbExecString) - + OUT=$("${MOBB_ARGS[@]}") + RETVAL=$? if [ $RETVAL -ne 0 ]; then exit $RETVAL fi - OUT=$(echo $OUT | tr '\n' ' ') - echo "fix-report-url=$OUT" >> $GITHUB_OUTPUT + OUT=$(echo "$OUT" | tr '\n' ' ') + echo "fix-report-url=$OUT" >> "$GITHUB_OUTPUT" echo "Mobb URL: $OUT" - - shell: bash -l {0} - - uses: Sibz/github-status-action@v1 + + shell: bash + env: + MOBB_API_KEY: ${{ inputs.api-key }} + REPORT_FILE: ${{ inputs.report-file }} + MOBB_PROJECT_NAME: ${{ inputs.mobb-project-name }} + MOBB_ORG_ID: ${{ inputs.organization-id }} + AUTO_PR: ${{ inputs.auto-pr }} + COMMIT_DIRECTLY: ${{ inputs.commit-directly }} + - uses: Sibz/github-status-action@33dcef57b1a833b6a2e50679cd8dece3193c0f03 # v1 with: authToken: ${{ inputs.github-token }} context: "Mobb fix report link" diff --git a/review/action.yml b/review/action.yml index b369709..cb1b093 100644 --- a/review/action.yml +++ b/review/action.yml @@ -27,27 +27,25 @@ runs: using: "composite" steps: # save report since the checkout step deletes it - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 id: vul-report-upload with: name: vul-report path: ${{ inputs.report-file }} - run: echo "Artifact ID is ${{ steps.vul-report-upload.outputs.artifact-id }}" - shell: bash -l {0} # needed since we get wrong hash. this step deletes the report file, so need to save it beforehand - - uses: actions/checkout@v3 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 name: checkout-to-branch with: ref: ${{ github.head_ref }} # restore the report file - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: vul-report path: results - - uses: actions/setup-node@v3.6.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 18 @@ -55,30 +53,43 @@ runs: run: | REPO=$(git remote get-url origin) REPO=${REPO%".git"} - GITHUB_TOKEN=${{ inputs.github-token }} - SCANNER=${{ inputs.scanner }} - COMMIT_HASH=$(git rev-parse $GITHUB_HEAD_REF) - PR_NUMBER=${{ github.event.pull_request.number }} - VUL_FILE_PATH=results/$(basename ${{ inputs.report-file }}) - MobbExecString="npx --yes mobbdev@latest review -r $REPO --ref $GITHUB_HEAD_REF --ch $COMMIT_HASH --api-key ${{ inputs.api-key }} -f $VUL_FILE_PATH --pr $PR_NUMBER --github-token ${{ inputs.github-token }} --scanner $SCANNER" + COMMIT_HASH=$(git rev-parse "$GITHUB_HEAD_REF") + VUL_FILE_PATH="results/$(basename "$REPORT_FILE")" + PR_NUMBER="${{ github.event.pull_request.number }}" + + MOBB_ARGS=( + npx --yes mobbdev@latest review + -r "$REPO" + --ref "$GITHUB_HEAD_REF" + --ch "$COMMIT_HASH" + --api-key "$MOBB_API_KEY" + -f "$VUL_FILE_PATH" + --pr "$PR_NUMBER" + --github-token "$GH_TOKEN" + --scanner "$SCANNER" + ) # Check if mobb-project-name exists and append it - if [ -n "${{ inputs.mobb-project-name }}" ]; then - echo "mobb-project-name specified: ${{ inputs.mobb-project-name }}" - MobbExecString+=" --mobb-project-name \"${{ inputs.mobb-project-name }}\"" + if [ -n "$MOBB_PROJECT_NAME" ]; then + echo "mobb-project-name specified: $MOBB_PROJECT_NAME" + MOBB_ARGS+=(--mobb-project-name "$MOBB_PROJECT_NAME") fi - # Output the final command string for debugging - echo "Mobb Command: $MobbExecString" - OUT=$(eval $MobbExecString || true) - OUT=$(echo $OUT | tr '\n' ' ') + OUT=$("${MOBB_ARGS[@]}" || true) + OUT=$(echo "$OUT" | tr '\n' ' ') - echo "fix-report-url=$OUT" >> $GITHUB_OUTPUT + echo "fix-report-url=$OUT" >> "$GITHUB_OUTPUT" echo "Mobb URL: $OUT" - shell: bash -l {0} + shell: bash + env: + MOBB_API_KEY: ${{ inputs.api-key }} + GH_TOKEN: ${{ inputs.github-token }} + SCANNER: ${{ inputs.scanner }} + REPORT_FILE: ${{ inputs.report-file }} + MOBB_PROJECT_NAME: ${{ inputs.mobb-project-name }} - - uses: Sibz/github-status-action@v1 + - uses: Sibz/github-status-action@33dcef57b1a833b6a2e50679cd8dece3193c0f03 # v1 if: ${{ startsWith(steps.run-npx-mobb-dev.outputs.fix-report-url, 'https://') }} with: authToken: ${{ inputs.github-token }} From 4ac6f2a8787b5ace0a5bb4349e745b8fe85281da Mon Sep 17 00:00:00 2001 From: Jonathan Santilli <1774227+jonathansantilli@users.noreply.github.com> Date: Tue, 7 Apr 2026 15:36:03 +0100 Subject: [PATCH 2/4] fix: extract URL from mobbdev CLI output to fix github-status-action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mobbdev CLI now prefixes its output with status messages like "🔌 [WebSocket Mode] Using WebSocket subscription..." before the URL. This caused github-status-action to receive an invalid target_url, failing with "Validation Failed". Extract just the https:// URL from the output using grep, matching the approach already used in codeql-mobb-fixer-action. Ref: E-1815 --- action.yml | 5 +++-- review/action.yml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/action.yml b/action.yml index 9ed1d0b..fac4154 100644 --- a/action.yml +++ b/action.yml @@ -90,8 +90,9 @@ runs: exit $RETVAL fi OUT=$(echo "$OUT" | tr '\n' ' ') - echo "fix-report-url=$OUT" >> "$GITHUB_OUTPUT" - echo "Mobb URL: $OUT" + MOBB_URL=$(echo "$OUT" | grep -oE 'https://[^ ]+' | head -1) + echo "fix-report-url=$MOBB_URL" >> "$GITHUB_OUTPUT" + echo "Mobb URL: $MOBB_URL" shell: bash env: diff --git a/review/action.yml b/review/action.yml index cb1b093..f16d1a5 100644 --- a/review/action.yml +++ b/review/action.yml @@ -77,9 +77,10 @@ runs: OUT=$("${MOBB_ARGS[@]}" || true) OUT=$(echo "$OUT" | tr '\n' ' ') + MOBB_URL=$(echo "$OUT" | grep -oE 'https://[^ ]+' | head -1) - echo "fix-report-url=$OUT" >> "$GITHUB_OUTPUT" - echo "Mobb URL: $OUT" + echo "fix-report-url=$MOBB_URL" >> "$GITHUB_OUTPUT" + echo "Mobb URL: $MOBB_URL" shell: bash env: From 315ed0616d0b1669e3fa0a6b98c49e2b6ffc49c2 Mon Sep 17 00:00:00 2001 From: Jonathan Santilli <1774227+jonathansantilli@users.noreply.github.com> Date: Tue, 7 Apr 2026 16:18:31 +0100 Subject: [PATCH 3/4] fix: add debug echo for branch name to verify injection fix Print REPO and BRANCH values so reviewers can verify that branch names containing shell metacharacters (e.g. test-$(id)) are treated as literal text and not executed. Ref: E-1815 --- action.yml | 3 +++ review/action.yml | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/action.yml b/action.yml index fac4154..531f785 100644 --- a/action.yml +++ b/action.yml @@ -42,6 +42,9 @@ runs: REPO=${REPO%".git"} BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + echo "REPO: $REPO" + echo "BRANCH: $BRANCH" + MOBB_ARGS=( npx --yes mobbdev@latest analyze --ci -r "$REPO" diff --git a/review/action.yml b/review/action.yml index f16d1a5..0927771 100644 --- a/review/action.yml +++ b/review/action.yml @@ -57,6 +57,11 @@ runs: VUL_FILE_PATH="results/$(basename "$REPORT_FILE")" PR_NUMBER="${{ github.event.pull_request.number }}" + echo "REPO: $REPO" + echo "BRANCH: $GITHUB_HEAD_REF" + echo "COMMIT_HASH: $COMMIT_HASH" + echo "PR_NUMBER: $PR_NUMBER" + MOBB_ARGS=( npx --yes mobbdev@latest review -r "$REPO" From 8305b5079fc2374c905e1191041c3bafbc2fe6a9 Mon Sep 17 00:00:00 2001 From: Jonathan Santilli <1774227+jonathansantilli@users.noreply.github.com> Date: Wed, 8 Apr 2026 10:55:59 +0100 Subject: [PATCH 4/4] fix: move github.event.pull_request.number to env block for consistency Move the last remaining ${{ github.event.* }} expression from run: blocks to env: blocks. While PR numbers are integers (not injectable), this ensures all github.event references consistently go through env vars, making the pattern easier to audit and maintain. Ref: E-1815 --- action.yml | 3 ++- review/action.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 531f785..8bcb2a2 100644 --- a/action.yml +++ b/action.yml @@ -77,7 +77,7 @@ runs: MOBB_ARGS+=(--commit-directly) # Check if the action is running in the context of a pull request - PR_ID="${{ github.event.pull_request.number }}" + PR_ID="$PR_NUMBER_ENV" if [ -n "$PR_ID" ]; then echo "Pull Request ID detected: $PR_ID" MOBB_ARGS+=(--pr-id "$PR_ID") @@ -105,6 +105,7 @@ runs: MOBB_ORG_ID: ${{ inputs.organization-id }} AUTO_PR: ${{ inputs.auto-pr }} COMMIT_DIRECTLY: ${{ inputs.commit-directly }} + PR_NUMBER_ENV: ${{ github.event.pull_request.number }} - uses: Sibz/github-status-action@33dcef57b1a833b6a2e50679cd8dece3193c0f03 # v1 with: authToken: ${{ inputs.github-token }} diff --git a/review/action.yml b/review/action.yml index 0927771..8bd7fa4 100644 --- a/review/action.yml +++ b/review/action.yml @@ -55,7 +55,7 @@ runs: REPO=${REPO%".git"} COMMIT_HASH=$(git rev-parse "$GITHUB_HEAD_REF") VUL_FILE_PATH="results/$(basename "$REPORT_FILE")" - PR_NUMBER="${{ github.event.pull_request.number }}" + PR_NUMBER="$PR_NUMBER_ENV" echo "REPO: $REPO" echo "BRANCH: $GITHUB_HEAD_REF" @@ -94,6 +94,7 @@ runs: SCANNER: ${{ inputs.scanner }} REPORT_FILE: ${{ inputs.report-file }} MOBB_PROJECT_NAME: ${{ inputs.mobb-project-name }} + PR_NUMBER_ENV: ${{ github.event.pull_request.number }} - uses: Sibz/github-status-action@33dcef57b1a833b6a2e50679cd8dece3193c0f03 # v1 if: ${{ startsWith(steps.run-npx-mobb-dev.outputs.fix-report-url, 'https://') }}