CVE-2024-1540: Improper Neutralization of Special Elements used in a Command ('Command Injection') (CWE-77)
value: A command injection vulnerability exists in the deploy+test-visual.yml workflow of the gradio-app/gradio repository, due to improper neutralization of special elements used in a command. This vulnerability allows attackers to execute unauthorized commands, potentially leading to unauthorized modification of the base repository or secrets exfiltration. The issue arises from the unsafe handling of GitHub context information within a `run` operation, where expressions inside `${{ }}` are evaluated and substituted before script execution. Remediation involves setting untrusted input values to intermediate environment variables to prevent direct influence on script generation.
CWE description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
Published: 2024-03-27T16:15Z
Repository: https://github.com/gradio-app/gradio
Language: YAML
Files changed: .github/workflows/deploy+test-visual.yml, .github/workflows/deploy-spaces.yml, .github/workflows/deploy-website.yml, .github/workflows/generate-changeset.yml, .github/workflows/test-hygiene.yml, .github/workflows/test-python.yml, .github/workflows/tests-js.yml
Commit date: 2024-02-09 18:01:44 +0000
Commit message: fix spaces comment and remove echos (#7373)

* remove unnecessary condition for deployment workflow

* remove unnecessary echo statements in GitHub Actions workflows

* fix website ci

* add condition to only run comment-spaces-start workflow if changes workflow outputs 'should_run' as 'true'
Diff: diff --git a/.github/workflows/deploy+test-visual.yml b/.github/workflows/deploy+test-visual.yml
index 47cd56108..22d183677 100644
--- a/.github/workflows/deploy+test-visual.yml
+++ b/.github/workflows/deploy+test-visual.yml
@@ -32,15 +32,10 @@ jobs:
         id: changes
         with:
           type: "visual"
           token: ${{ secrets.GITHUB_TOKEN }}
           name: "UI Tests"
-      - name: echo github context
-        if: always()
-        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
-  
-
   comment-chromatic-start:
     uses: "./.github/workflows/comment-queue.yml"
     needs: changes
     if: ${{ needs.changes.outputs.should_run == 'true' }}
     secrets:
diff --git a/.github/workflows/deploy-spaces.yml b/.github/workflows/deploy-spaces.yml
index ae9f1933e..c457c2cf3 100644
--- a/.github/workflows/deploy-spaces.yml
+++ b/.github/workflows/deploy-spaces.yml
@@ -23,26 +23,25 @@ jobs:
       pr_number: ${{ steps.changes.outputs.pr_number }}
       source_branch: ${{ steps.changes.outputs.source_branch }}
       source_repo: ${{ steps.changes.outputs.source_repo }}
       merge_sha: ${{ steps.changes.outputs.merge_sha }}
       mergeable: ${{ steps.changes.outputs.mergeable }}
+      found_pr: ${{ steps.changes.outputs.found_pr }}
     steps:
       - uses: actions/checkout@v4
       - uses: "gradio-app/gradio/.github/actions/changes@main"
         id: changes
         with:
           type: "functional"
           name: "deploy / spaces"
           token: ${{ secrets.GITHUB_TOKEN }}
           commit_status: false
-      - name: echo github context
-        if: always()
-        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
   
   comment-spaces-start:
     needs: changes
     uses: "./.github/workflows/comment-queue.yml"
+    if: ${{ needs.changes.outputs.should_run == 'true' }}
     secrets:
       gh_token: ${{ secrets.COMMENT_TOKEN }}
     with:
       pr_number: ${{ needs.changes.outputs.pr_number }}
       message: spaces~pending~null
@@ -125,14 +124,11 @@ jobs:
         echo ${{ github.event.workflow_run.conclusion }}
     
   comment-spaces-success:
     uses: "./.github/workflows/comment-queue.yml"
     needs: [deploy-spaces, changes]
-    if: >
-      github.event.workflow_run.event == 'pull_request' &&
-      github.event.workflow_run.conclusion == 'success' &&
-      needs.deploy-spaces.result == 'success'
+    if: needs.deploy-spaces.result == 'success' && needs.changes.outputs.found_pr == 'true'
     secrets:
       gh_token: ${{ secrets.COMMENT_TOKEN }}
     with:
       pr_number: ${{ needs.changes.outputs.pr_number }}
       message: spaces~success~${{ needs.deploy-spaces.outputs.space_url }}
@@ -147,11 +143,11 @@ jobs:
         pip install "gradio-client @ git+https://github.com/gradio-app/gradio@${{ needs.changes.outputs.sha }}#subdirectory=client/python"
         ```
   comment-spaces-failure:
     uses: "./.github/workflows/comment-queue.yml"
     needs: [deploy-spaces, changes]
-    if: always() && needs.deploy-spaces == 'failure'
+    if: always() && needs.deploy-spaces == 'failure' && needs.changes.outputs.found_pr == 'true'
     secrets:
       gh_token: ${{ secrets.COMMENT_TOKEN }}
     with:
       pr_number: ${{ needs.changes.outputs.pr_number }}
       message: spaces~failure~https://github.com/gradio-app/gradio/actions/runs/${{github.run_id}}/
diff --git a/.github/workflows/deploy-website.yml b/.github/workflows/deploy-website.yml
index 25bd49133..776c2216f 100644
--- a/.github/workflows/deploy-website.yml
+++ b/.github/workflows/deploy-website.yml
@@ -37,14 +37,10 @@ jobs:
         id: changes
         with:
           type: "website"
           token: ${{ secrets.GITHUB_TOKEN }}
           commit_status: false
-      - name: echo github context
-        if: always()
-        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
-
   comment-deploy-start:
     needs: changes
     uses: "./.github/workflows/comment-queue.yml"
     secrets:
       gh_token: ${{ secrets.COMMENT_TOKEN }}
@@ -76,16 +72,10 @@ jobs:
           export AWS_DEFAULT_REGION=us-west-2
           version=$(jq -r .version js/_website/src/lib/json/version.json)
           aws s3 cp ./js/_website/src/lib/json/ s3://gradio-docs-json/$version/ --recursive
       - name: Install Vercel CLI
         run: pnpm install --global vercel@latest
-      - name: echo outputs
-        run: |
-          echo "source_repo=${{ needs.changes.outputs.source_repo }}"
-          echo "source_branch=${{ needs.changes.outputs.source_branch }}"
-          echo "found_pr=${{ needs.changes.outputs.found_pr }}"
-          echo "pr_number=${{ needs.changes.outputs.pr_number }}"
       # preview
       - name: Pull Vercel Environment Information
         shell: bash
         if: needs.changes.outputs.found_pr == 'true'
         run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
diff --git a/.github/workflows/generate-changeset.yml b/.github/workflows/generate-changeset.yml
index 1da8d2d12..9745bc92c 100644
--- a/.github/workflows/generate-changeset.yml
+++ b/.github/workflows/generate-changeset.yml
@@ -26,14 +26,10 @@ jobs:
     - name: get pr details
       id: pr_details
       uses: gradio-app/github/actions/find-pr@main
       with:
         github_token: ${{ secrets.GITHUB_TOKEN }}
-    - name: echo github context
-      if: always()
-      run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
-
   comment-changes-start:
     uses: "./.github/workflows/comment-queue.yml"
     needs: get-pr
     secrets:
       gh_token: ${{ secrets.COMMENT_TOKEN }}
diff --git a/.github/workflows/test-hygiene.yml b/.github/workflows/test-hygiene.yml
index ec28cd5db..151a72585 100644
--- a/.github/workflows/test-hygiene.yml
+++ b/.github/workflows/test-hygiene.yml
@@ -30,14 +30,10 @@ jobs:
       - uses: "gradio-app/gradio/.github/actions/changes@main"
         id: changes
         with:
           type: "all"
           token: ${{ secrets.GITHUB_TOKEN }}
-      - name: echo github context
-        if: always()
-        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
-  
   test-hygiene:
     name: "test-hygiene"
     runs-on: ubuntu-latest
     needs: changes
     if: needs.changes.outputs.should_run == 'true'
diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml
index 3c8b14966..e0cdcd688 100644
--- a/.github/workflows/test-python.yml
+++ b/.github/workflows/test-python.yml
@@ -37,15 +37,10 @@ jobs:
         id: changes
         with:
           type: "gradio"
           name: "test / python / linux"
           token: ${{ secrets.GITHUB_TOKEN }}
-      - name: echo github context
-        if: always()
-        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
-
-  
   test-python:
     needs: [changes]
     if: needs.changes.outputs.should_run == 'true'
     name: "test-python-${{ matrix.os }}-${{ matrix.test-type == 'flaky' && 'flaky' || 'not-flaky'}}"
     strategy:
diff --git a/.github/workflows/tests-js.yml b/.github/workflows/tests-js.yml
index bec513471..49218d587 100644
--- a/.github/workflows/tests-js.yml
+++ b/.github/workflows/tests-js.yml
@@ -37,14 +37,10 @@ jobs:
       - uses: "gradio-app/gradio/.github/actions/changes@main"
         id: changes
         with:
           type: "js"
           token: ${{ secrets.GITHUB_TOKEN }}
-      - name: echo github context
-        if: always()
-        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
-
   test-js:
     needs: changes
     if: needs.changes.outputs.should_run == 'true'
     name: test-js
     runs-on: ubuntu-22.04

Vulnerable code:       - name: echo github context
        if: always()
        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
  

      - name: echo github context
        if: always()
        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
    if: >
      github.event.workflow_run.event == 'pull_request' &&
      github.event.workflow_run.conclusion == 'success' &&
      needs.deploy-spaces.result == 'success'
    if: always() && needs.deploy-spaces == 'failure'
      - name: echo github context
        if: always()
        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"

      - name: echo outputs
        run: |
          echo "source_repo=${{ needs.changes.outputs.source_repo }}"
          echo "source_branch=${{ needs.changes.outputs.source_branch }}"
          echo "found_pr=${{ needs.changes.outputs.found_pr }}"
          echo "pr_number=${{ needs.changes.outputs.pr_number }}"
    - name: echo github context
      if: always()
      run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"

      - name: echo github context
        if: always()
        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"
  
      - name: echo github context
        if: always()
        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"

  
      - name: echo github context
        if: always()
        run: echo "${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}-${{ github.workflow_ref }}"

Fixed code:       found_pr: ${{ steps.changes.outputs.found_pr }}
    if: ${{ needs.changes.outputs.should_run == 'true' }}
    if: needs.deploy-spaces.result == 'success' && needs.changes.outputs.found_pr == 'true'
    if: always() && needs.deploy-spaces == 'failure' && needs.changes.outputs.found_pr == 'true'