Observations
GitHub Actions is an automation platform directly integrated into GitHub repositories. It allows you to create custom workflows to automate various tasks within your software development lifecycle, such as building, testing, and deploying code. These workflows are defined in YAML files and are triggered by events within your repository, like a code push or a pull request.
Certain parameters, such as issue title, are considered unsafe because an unauthorized user could fully control them. Furthermore, GitHub Action runners operate with varying levels of permissions and secret access, determined by the "permissions" configuration in the YAML file, authorization settings at the repository level, and the specific event that triggered the action (e.g., pull_request versus pull_request_target).
We noticed that the main_matrix.yml GitHub Action is triggered by the pull_request_target
event, which has extensive permissions, and can be initiated by an attacker who forked the repository and created a pull request. In the shell code execution part, user-controlled input is interpolated unsafely into the code.
run: |
if [[ "${{ github.head_ref }}" == "" ]]; then
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}})
else
TARGETS=$(./bin/generate_ci_matrix.py ${{matrix.arch}} quick)
fi
echo "Name: ${{ github.ref_name }} Base: ${{ github.base_ref }} } Ref: ${{ github.ref }} Targets: $TARGETS"
echo "${{matrix.arch}}=$(jq -cn --argjson environments "$TARGETS" '{board: $environments}')" >> $GITHUB_OUTPUT
Exploitation
An attacker could create a pull request from a fork with a branch name such as $(printenv>&2)
that will print the environment variable of the runner or $({git,config,--get,http.https://github.com/.extraheader}>&2)
to exfiltrate the GitHub token. The >&2
is meant to print the output to stderr
since it is interpolated inside a string, and using the curly brackets when executing a command with an argument is needed due to GitHub’s branch name limitation.
Note: We reproduced the vulnerability in our own environment. We did not try to exploit this on the Meshtastic/firmware repository.
Impact
The action utilizes the pull_request_target
trigger, which has extensive permissions. If this were to be exploited, attackers could inject unauthorized code into the repository. This could have significant negative impacts on users, such as the deployment of backdoors, the distribution of malware, and other security compromises.
Recommendations
One recommended way to handle untrusted user input in GitHub Actions is to first assign it to an intermediate environment variable and only then use it in the execution step.
jobs:
safe-echo-body:
runs-on: ubuntu-latest
steps:
- env:
BODY: ${{ github.event.issue.body }}
run: |
echo "$BODY"
Be aware of an interesting pitfall, and don't interpolate environment variables using ${{ env.BODY }}
.
Observations
GitHub Actions is an automation platform directly integrated into GitHub repositories. It allows you to create custom workflows to automate various tasks within your software development lifecycle, such as building, testing, and deploying code. These workflows are defined in YAML files and are triggered by events within your repository, like a code push or a pull request.
Certain parameters, such as issue title, are considered unsafe because an unauthorized user could fully control them. Furthermore, GitHub Action runners operate with varying levels of permissions and secret access, determined by the "permissions" configuration in the YAML file, authorization settings at the repository level, and the specific event that triggered the action (e.g., pull_request versus pull_request_target).
We noticed that the main_matrix.yml GitHub Action is triggered by the
pull_request_target
event, which has extensive permissions, and can be initiated by an attacker who forked the repository and created a pull request. In the shell code execution part, user-controlled input is interpolated unsafely into the code.Exploitation
An attacker could create a pull request from a fork with a branch name such as
$(printenv>&2)
that will print the environment variable of the runner or$({git,config,--get,http.https://github.com/.extraheader}>&2)
to exfiltrate the GitHub token. The>&2
is meant to print the output tostderr
since it is interpolated inside a string, and using the curly brackets when executing a command with an argument is needed due to GitHub’s branch name limitation.Note: We reproduced the vulnerability in our own environment. We did not try to exploit this on the Meshtastic/firmware repository.
Impact
The action utilizes the
pull_request_target
trigger, which has extensive permissions. If this were to be exploited, attackers could inject unauthorized code into the repository. This could have significant negative impacts on users, such as the deployment of backdoors, the distribution of malware, and other security compromises.Recommendations
One recommended way to handle untrusted user input in GitHub Actions is to first assign it to an intermediate environment variable and only then use it in the execution step.
Be aware of an interesting pitfall, and don't interpolate environment variables using
${{ env.BODY }}
.