Exploring CI/CD Vulnerabilities in github actions
I hope this message finds you well. Today, I'm thrilled to share my journey and insights into exploring CI/CD vulnerabilities in GitHub Actions.
Getting started
To start with actions It is crucial to understand the intricacies of action workflows and familiarize yourself with their functionality and the significance of each event. Crafting sample workflows can significantly aid comprehension.
To help you get started, I have a YouTube playlist with informative videos that will guide you in getting acquainted with the action workflow
Understanding Workflow Events
I will only talk about two workflow events that will lead to RCE if misconfigured in action workflows
pull_request_target
and workflow_run
events
configurations for action:
Let's talk about the Configurations that are used for action.
The default permissions allow first-time contributors to run the action runners without any approval from the maintainers. Most repositories have this default configuration. You can look at the pull requests that are being opened to confirm if you need to become a first-time contributor or not to exploit it.
To become a first contributor you need to have a pull request merged before you create the exploit pull request. I mostly prefer spelling mistakes and sometimes little code changes.
Running Attacker Code
pull_request_target
: This event is same aspull_request
but the main difference is that it has a write permission for the tokens, So an attacker can execute Malicious commands with write permissions if the event is misconfigured.
Here is a YAML file that is vulnerable to malicious execution by pull_request_target.
Example 1: Vulnerability via pull_request_target
on:
pull_request_target
jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }} # from here on it will take the attacker code as it is checking out the untrusted input
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm install
- name: Build docs
run: npm run create-docs
Explanation:
ref: ${{ github.event.pull_request.head.sha }}
From this part the action will run on the attacker forked code base as it is using head.sha
which will take the attacker pull request as an input and make the base repo action to run the attacker's fork code here.
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: '16'
From this, the code will set up the npm environment from the action runner from the attacker's code.
- name: Install dependencies
run: npm install
- name: Build docs
run: npm run create-docs
The potentially untrusted code is being run during the npm install and npm run as the referenced packages are controlled by the author of the PR.
Exploitation
Now in the forked Repo, you can modify your input in package.json and create a pull request.
"scripts": {
"create-docs": "echo 'your code'"
}
2.workflow_run
: This event allows a user to trigger privileged workflows. It triggers when the status of the other workflow is complete/requested and can be triggered from a forked workflow.
Here is a YAML file that is vulnerable to malicious execution by workflow_run
Example 2: Vulnerability via workflow_run
name: Deploy docs
on:
workflow_run:
workflows: ['Publish Package']
types: [completed]
jobs:
deploy-docs:
runs-on: ubuntu-latest
if: ${{ github.event.workflow_run.conclusion == 'success' }} #if the workflow is successfully completed then it will start the rest of the tasks in the job
steps:
- name: Checkout
uses: actions/checkout@v2
with:
ref: ${{ github.event.workflow_run.head_sha }} # checkout specific commit
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: '16'
- name: Install dependencies
run: npm install
- name: Build docs
run: npm run create-docs
Explantion:
workflow_run:
workflows: ['Publish Package']
types: [completed]
if: ${{ github.event.workflow_run.conclusion == 'success' }}
As the original workflow Publish Package
is triggered by pull_request
and runs the vulnerable workflow after successful completion we can create the same exploit as we created for the pull_request_target
.
Exploitation
modifying package.json file and create the pull request from fork
"scripts": {
"create-docs": "echo 'your code'"
}
Conclusion:
In this post, we've explored how misconfigured GitHub Actions workflows can lead to vulnerabilities, such as Remote Code Execution (RCE). Specifically, we've discussed the risks associated with the pull_request_target and workflow_run events. These examples underscore the importance of understanding and properly configuring CI/CD pipelines to prevent potential security breaches.
To mitigate these risks, avoid checking out untrusted code within your action workflows. Assign write permissions only when absolutely necessary, and always validate and sanitize inputs to your workflows.
There are many other potential exploit scenarios and events in GitHub Actions that could lead to vulnerabilities. It’s crucial to continuously review and update your security practices to safeguard your CI/CD pipelines.
Reference:
https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability
https://cloud.hacktricks.xyz/pentesting-ci-cd/github-security/abusing-github-actions