
"GitHub Office" by DASPRiD is licensed under CC BY 2.0.
GitHub Actions is an easy way to automate workflows on GitHub. From issue triage to continuous deployment, Actions offers a wide variety of triggers and functionality. However, this ease of configurability comes with numerous security risks.
Certain insecure workflows can allow attackers to execute workflows against your repository and potentially exfiltrate sensitive data. Known as “Pwn Requests”, a combination of insecure GitHub Actions triggers with sensitive content can lead to severe security threats. Fortunately, there are ways to detect and mitigate this issue.
We’ve seen AI-based attacks against GitHub runners in open-source projects that exploit these exact weaknesses.
In this post, we will discuss GitHub Actions security, looking at how some default settings and concepts can lead to security threats, ways to spot dangerous patterns, and tips for fixing them.
How does GitHub Actions work?
GitHub Actions is a pipeline for executing workflows within a GitHub repository. They are very commonly used for running Continuous Integration (CI) tests, issue triage, and other types of workflow automation.
Actions are configured by creating a .github/workflows/actions.yml file within a repository. They can be triggered by several actions: new issues, issue comments, pull requests, and more.
They run using a GitHub token that is limited to performing specific actions within the repository, such as reading or writing data. While these permissions can be configured, many legacy repositories default to granting the token write access. Additionally, Actions can have access to secrets defined for the repository.
This combination of functionality can lead to a dangerous vulnerability: attacker-controlled input (via a maliciously crafted pull request or issue) executing with a highly privileged GitHub token, potentially exposing secrets or compromising the repository. These are known as “Pwn Requests”.
Exploitable GitHub Actions Workflows
GitHub Actions workflows become vulnerable if they allow untrusted inputs to automatically run with unsafe permissions. When a malicious event triggers a vulnerable workflow, it can allow an attacker to exfiltrate repository secrets or push commits to your repository.
A few Actions triggers in particular are problematic:
pull_request_target is a trigger that runs when a new Pull Request is created against your repository. However, unlike the pull_request trigger, pull_request_target runs within the context of your current repository. This means that workflows that use the pull_request_target trigger are granted access to a GitHub token and potentially other CI secrets scoped to your repository.
pull_request_target is so unsafe that the entire concept of Pwn Requests is based on this trigger. A workflow is vulnerable if pull_request_target directly checks out code from the pull request with actions/checkout and ${{github.event.pull_request.head.ref}}. When this code is run, it is run with a GitHub token that has permissions to access your repository. This makes it possible for malicious code in a forked repository's pull request to compromise the target repository by exploiting these permissions. To mitigate this risk, it is crucial to avoid checking out external pull request code with elevated privileges or restrict the token's permissions explicitly using fine-grained settings.
The workflow_run trigger enables one GitHub Actions workflow to start another workflow automatically after it completes. This can become dangerous if the output from the first workflow, such as data or files it generates, is used in the second workflow without proper validation or safety checks. For example, if the first workflow saves a file with untrusted content and the second workflow processes that file assuming it is safe, malicious data could be introduced. This could lead to unintended actions like exposing sensitive information or altering repository content.
issue, issue_comment, discussion, and discussion_comment can be unsafe if they are improperly injected into a workflow. For example, if an issue comment is sent to GitHub Models, this can result in a prompt injection vulnerability.
Detecting Vulnerable GitHub Actions Workflows
The main issue with GitHub Actions is when content from an untrusted user is executed unsafely with elevated permissions. To differentiate between legitimate use cases that could be false positives, such as CI jobs on an open source repository, and truly vulnerable workflows, audit them with three questions in mind:
- Am I triggering workflows based on untrusted actors?
Untrusted actors can create pull requests, issues, discussions, or forks against an open source repository. If an untrusted actor can trigger your workflow, this significantly elevates the risk posed by the workflow. Even if you are not executing attack-supplied content (see point 3), this may allow an untrusted actor to DoS your repository.
- Does the workflow run with elevated permissions?
GitHub Actions workflows have configurable GitHub token permissions. A workflow with write access to the underlying repository may be riskier than one with only read access. Likewise, if a workflow does not need access to any GitHub secrets, it should not be granted access to any secrets.
- Am I executing user-supplied content?
If the content being executed in a workflow originates from a non-trusted user, such as the content of a pull request or a comment on a public repository, this elevates the risk of the workflow. Malicious users may hide directives that exfiltrate secrets or attempt to write to the underlying repository if executed.
If any workflows use untrusted input and have write permissions, this may indicate that they are vulnerable and should be re-architected. Separate workflows that are triggered from untrusted actors from those that require write or more permissions to reduce risk.
Consider also enabling static analysis tools to detect these vulnerabilities automatically. Tools like Zizmor, Semgrep, or CodeQL have rulesets specifically designed for detecting vulnerable Actions workflows.
Rewriting a Vulnerable Actions Workflow
Architecting secure Actions workflows involves choosing the right triggers, appropriate permissions, and actions for a given threat model.
Here is an example of a GitHub Actions workflow that is vulnerable:
name: Unsafe Workflow
on:
pull_request_target:
jobs:
check:
permissions:
contents: write
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.ref }}
This workflow is vulnerable as:
- It triggers from the
pull_request_targetevent, which can be initiated by any user on an open source repository - It uses the
pull_request_targetevent and runs with a GitHub token that has write permissions.pull_request_targetruns in the context of the base branch on a repository, rather than the merge commit, which means that the workflow executes with elevated permissions on the underlying repository. - The actions/checkout action checks out the code directly from the pull request. Due to the way the checkout action runs, this may automatically execute an attacker’s code from their pull request.
To secure this workflow, we should use a safer trigger; the GitHub token’s permissions should be reduced; and the checkout action should use the merge commit. The pull_request trigger is safer than pull_request_target because it executes in the fork's context, avoiding the exposure of secrets from the base repository. Reducing the GitHub token's permissions to "read-only" prevents attackers from modifying repository content. Lastly, using the merge commit for checkout ensures tests run against the code as it would appear after merging the pull request into the base branch, validating integration reliability.
Here is the same workflow updated to be secure.
name: Safe Workflow
on:
pull_request:
branches:
- main
jobs:
check:
permissions:
contents: read
steps:
# Check out the merge commit to ensure the code being tested is the result of merging the PR with the base branch
- uses: actions/checkout@v3
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
Best Practices for Writing Secure Actions Workflows
When writing GitHub Actions workflows, follow these best practices to avoid vulnerabilities:
- Avoid using risky Actions triggers.
To minimize risk, avoid using Actions workflow triggers from untrusted user events, especially on open source repositories. Triggers like pull_request_target should be used sparingly and with extreme caution.
- Use the minimum set of permissions in all Actions workflows.
Set up the GitHub token for any Actions workflow to use only the minimum permissions necessary. Do not allow write access for any workflow unless strictly necessary.
- Use secure GitHub Actions and workflows.
Supply chain issues are a growing vector for attacks, so audit the Actions in use in your workflow for supply chain security signals. Check the source repository’s security history and contributor trustworthiness.
If you are using GitHub Models or AI in your agents, consider using a secure workflow builder like GitHub Next Agentic Workflows.
- Set secure repository and organization settings for Actions workflows.
GitHub allows you to configure several Action security settings. The two that should be set are:
Approval for running fork pull request workflows from contributors:
This setting will restrict Actions workflows from being triggered by unauthorized users on your repositories, minimizing the risk from malicious users.
Default GitHub token permissions:
The default GitHub token permissions should be set to read-only. This will prevent new workflows from being created with overpermissioned tokens.
- Set up static analysis rules to detect security regressions.
Configure static analysis to detect new vulnerabilities proactively. Consider using a tool like Zizmor, Semgrep, or CodeQL.
Conclusion
GitHub Actions are a powerful way to build workflows on GitHub, but they can lead to significant security risks if misconfigured. Improper triggers and overpermissioned GitHub tokens can result in severe security compromise due to data exfiltration or repository overwrites. Ensuring that your workflows use the principles of least privilege and supply chain security is crucial for maintaining a secure CI pipeline.
If properly setting up your GitHub Actions workflows feels challenging, consider consulting with a security expert to ensure your pipelines are protected. Reach out to Cloud Security Partners today for a trusted security partner.
Stay in the loop.
Subscribe for the latest in AI, Security, Cloud, and more—straight to your inbox.
