The Build Pipeline Blind Spot
The supply chain security conversation usually stops at CVEs in runtime dependencies. SBOMs track what ships in the final artifact. SCA tools flag what’s vulnerable. That work is mature enough to be mandated by the US government. But build pipelines, the tools and scripts that run at compile time and never land in the final artifact, get almost no attention. Only 20 CVEs exist for GitHub Actions, while over 30,000 public actions are in the marketplace. That gap was the starting point for this research into zero-days hiding in build pipelines.
Threat Modeling Build Pipelines with SLSA
The SLSA framework, Supply Chain Levels for Software Artifacts, published by Google through the Linux Foundation, maps threats across the full software development lifecycle. Developers push code to GitHub, open pull requests, trigger CI builds, and publish artifacts to registries. Dependencies pulled at build time, including compilers, linters, and test frameworks, never land in the shipped artifact but still run with full pipeline permissions. Build tools like GCC were designed for trusted source files. GitHub’s model now routes anonymous contributions through those same tools. That mismatch is what this research targets.
How Pull Request Injection Attacks Work
The most common attack vector targets GitHub Actions workflows triggered by pull_request_target or workflow_run events. Unlike pull_request, these events run with access to repository secrets even when triggered from a fork. If the workflow checks out untrusted fork code and interpolates attacker-controlled values into a bash or JavaScript script, RCE follows. The attacker controls the branch name and can embed $(command) payloads. From there, the goal is to exfiltrate build secrets or tamper with the build artifact directly without extracting credentials at all.
Scanning 350,000 Repos for Build Pipeline Vulnerabilities
BoostSecurity built Package Supply to find these vulnerabilities at scale. The system cloned approximately 350,000 open source repos, parsed GitHub Actions workflow files, and ran static analysis across all of them. Terraform modules and providers got special attention because they provision cloud infrastructure and are just public GitHub repos under the hood. Results went into BigQuery for querying, then into Neo4j to map transitive attack paths. A vulnerability in one GitHub Action used as a dependency by another expands the blast radius quickly. Out of 350,000 repos, roughly 24,000 to 25,000 used risky trigger events, and thousands had injection points.
A Top-Five Terraform Module Backdoored in One PR
The demo used a real vulnerability pattern from a top-five Terraform registry module. The attacker forks the module’s GitHub repo, adds a .gomplate.yaml file containing an arbitrary bash command via gomplate’s postExec feature, and opens a PR as a typo fix. CI triggers automatically. One action in the dependency chain runs gomplate, executing the payload. The attacker publishes a backdoored version via git tag, then force-pushes their fork branch to erase evidence. The backdoor sits on a dangling commit no branch references. A victim running terraform plan surrenders Google Cloud admin credentials.
Detection Tools and Remediation
BoostSecurity released Poutine as an open source static analysis tool for build pipelines. It supports GitHub Actions, GitLab, Azure DevOps, and Tekton. It catches injection, unpinned code execution, and known vulnerable components. It scans an entire organization in minutes. Messi Poutine is a companion CTF with 25 challenges for learning exploitation. For remediation: use pull_request instead of pull_request_target for untrusted contributors, set workflow permissions to read-only at the top level, segment secrets by environment, use OIDC instead of personal access tokens, and never enable self-hosted runners on public repos without ephemeral VMs.
Q&A
Will pipeline-security scanning tools eventually merge into IaC scanning products? Tools like Checkov do basic pipeline checks, but Poutine is more specialized because Semgrep’s rule language lacks the power to find many obvious injection patterns, which is why BoostSecurity wrote a dedicated tool. ▶ Watch (39:47)
How did the attacker force-push during the demo? The force-push was on the attacker’s own fork, not the upstream repo. With RCE and a token that has write permissions, the attacker can also push to branches in the upstream, which is precisely where branch protection limits the damage. ▶ Watch (40:55)
Do similar injection attacks apply to Jenkins and other CI systems? Yes. Poutine supports GitHub Actions, GitLab, Tekton, and Azure DevOps, with nearly identical rules across all four. GitLab is a partial exception: merge requests run unprivileged by default, but one click moves execution into the privileged context, making it a social engineering problem rather than a purely technical one. ▶ Watch (43:58)
What could GitHub build to prevent these attacks? Native runtime protection, similar to StepSecurity’s Harden Runner, would let teams declare expected outbound network calls and process allowlists as pipeline policy, blocking exfiltration even after RCE. ▶ Watch (45:18)
Notable Quotes
cicd systems should be treated like production systems with the same level of scrutiny because in many cases they produce artifacts that are consumed by production systems François Proulx · ▶ Watch (11:50)
the intuition that it really cannot be the case that there is you only 20 vulnerable GitHub actions well while there is you know 20,000 30,000 uh so it it didn’t it didn’t look right François Proulx · ▶ Watch (4:49)
we still see a lot of curl pipe bash basically pulling uh random scripts from you know different sources and blindly executing it without performing any kind of cryptog graphic signature verification on it François Proulx · ▶ Watch (10:48)
at that point module B is back doored and a new version has been published François Proulx · ▶ Watch (27:06)
Key Takeaways
- Build pipeline dependencies have almost no CVE coverage despite affecting every artifact shipped to production.
- GitHub Actions workflows triggered by
pull_request_targetexpose secrets to fork-originated code, enabling RCE via branch-name injection. - Poutine, an open source static analysis tool, scans CI/CD pipelines for injection, vulnerable components, and misconfigured permissions in minutes.
About the Speaker(s)
François Proulx is VP of Security Research at BoostSecurity, where he leads the Supply Chain research team. With nearly 15 years of experience building AppSec programs for large corporations such as Intel and startups, he has been in the heat of the action as the DevSecOps movement has matured.