A researcher with no organization membership, no special privileges, and nothing more than a free GitHub account could leave a pull request comment on Microsoft's Azure Sentinel repository and walk away with a non-expiring GitHub App key. The same class of bug let an anonymous PR against Google's AI Agent Development Kit escalate into roles/owner on a live Google Cloud project. Cloudflare's Workers SDK, Apache Doris, and the Python Software Foundation's Black formatter all had their own version of the same flaw.
Penetration-testing firm Novee Security calls the pattern Cordyceps, and it isn't one bug — it's a systemic class of CI/CD misconfiguration the firm found by scanning roughly 30,000 high-impact GitHub repositories. It flagged 654 of them and confirmed more than 300 fully exploitable, at organizations that included Microsoft, Google, Apache, Cloudflare, and the Python Software Foundation. Every one of those chains started the same way: a workflow trusted input from a pull request as if it came from a maintainer, and ran it with a maintainer's permissions.
What Cordyceps actually is
Novee's research groups the exploitable pattern into four recurring shapes, all rooted in the same mistake — a workflow treats attacker-controlled input as trusted:
- Command injection. Attacker-controlled text — a branch name, a PR title, a comment body — gets interpolated directly into a shell command inside a workflow step, instead of being passed in as a quoted environment variable.
- Code injection. The same untrusted input gets interpolated into inline JavaScript inside an
actions/github-scriptstep and evaluated at runtime, which is command injection's scripting-language sibling and just as exploitable. - Broken authorization. A workflow has an authorization check, but the check silently fails — it reads a property that doesn't exist on the event type actually triggering the workflow, so the gate never fires and every request passes.
- Cross-workflow privilege escalation. A low-privilege workflow (one that safely checks out fork PR code) passes data — via artifacts, step outputs, or environment files — into a second, high-privilege workflow that trusts it without re-validating it.
The trigger underneath most of these is pull_request_target (or workflow_run, its cousin). Unlike a plain pull_request event, pull_request_target runs in the context of the base repository — full GITHUB_TOKEN scope, real secrets, the works — even when it's reacting to a fork. GitHub's own documentation has warned for years that checking out untrusted fork content inside one of these workflows hands an attacker the workflow's full privileges. Security researchers call the resulting exploit a "pwn request." Cordyceps is what happens when that warning gets ignored at scale, including by some of the org accounts writing the warning.
Five confirmed compromises, five different blast radii
Novee didn't stop at scanning — it validated exploitability end-to-end against real repositories, then worked with each vendor on fixes before publishing on June 23, 2026. The five disclosed cases show how differently the same root cause pays off depending on what a repo's CI actually has access to:
| Organization / Project | Trigger | What an anonymous attacker got |
|---|---|---|
| Microsoft — Azure Sentinel | A PR comment | Anonymous code execution on Microsoft's CI, plus theft of a non-expiring GitHub App key — persistent write access to security content Microsoft ships to customers |
| Google — AI Agent Development Kit | A single pull request | Code execution that escalated to roles/owner on the associated Google Cloud project |
| Apache Doris | Two independent chains | Zero-click credential exfiltration via a comment trigger, plus a separate fork-PR path that stole a write-permission token |
| Cloudflare — Workers SDK | A crafted branch name | Arbitrary command execution on Cloudflare's CI runners |
| Python Software Foundation — Black | A single pull request | Theft of the automation token used to post, approve, and manipulate pull requests |
Two of those — Microsoft and Apache Doris — required literally zero clicks from a maintainer once the PR or comment existed. The rest needed a PR to sit in the queue, not to be merged or even reviewed. Downstream, Novee's assessment lists the consequences that fall out of stolen CI credentials at this scale: publishing malicious packages to npm, PyPI, crates.io, container registries, and Helm; pushing directly to protected branches; forging CI checks to bypass merge gates; and pivoting into cloud credentials across AWS, GCP, and Netlify. A compromised build pipeline isn't just a compromised repo — it's a foothold into every artifact and every cloud account that pipeline is trusted to touch.
GitHub's fix: actions/checkout stops fetching fork code by default
Five days before Novee's disclosure, GitHub shipped a structural mitigation rather than waiting for individual repos to catch every misconfigured workflow. actions/checkout v7, released June 18, 2026, refuses to fetch fork pull request code inside pull_request_target and workflow_run workflows when it detects the specific patterns that make a pwn request possible — ref: refs/pull/<PR>/merge, a fork PR's head SHA, or an explicit fork repository name.
The rollout has teeth on a timeline:
- v7 is generally available now — any workflow pinned to it gets the protection immediately.
- July 20, 2026 — the same protection backports to every supported major version tag (
@v4,@v3, etc., everything exceptv1), so workflows that never touched their checkout config still get covered automatically. - Workflows with a legitimate reason to check out fork code at elevated privilege have to opt out explicitly, by adding
allow-unsafe-pr-checkout— turning a silent footgun into a decision someone has to type out and justify.
It's a meaningful floor-raise. It's also not a full fix: it closes the specific "checkout fetches attacker code" step, not the command-injection or broken-authorization patterns Novee found in workflows that never call checkout on fork content at all. A workflow that interpolates a PR title straight into a shell command is exploitable with no fork checkout in sight.
The audit a git-push platform's own build pipeline needs to run
None of this is abstract for a platform whose entire product is "push a git repo, we build and run it." A self-hosted PaaS's CI — the workflows that build the CLI, the Cluster API providers, the release pipeline — is exactly the shape Cordyceps targets: repos with real deploy secrets, public enough to take PRs from strangers, run by workflows nobody has re-read since the day they were written. This checklist is general — it applies to any GitHub Actions pipeline, not just bex's — but it's the concrete audit this class of vulnerability demands before assuming "we use GitHub Actions like everyone else" is a safe default:
- Grep every workflow for
pull_request_targetandworkflow_run. Each hit needs a documented reason. If the workflow doesn't need base-repo secrets or write access, switch it to plainpull_request, which runs in the fork's own low-privilege context. - Check every workflow has a top-level
permissions:block, scoped down. GitHub's default is broad read/write access unless a workflow narrows it explicitly.permissions: contents: read(adding only what a specific job needs) turns a successful injection into a much smaller blast radius than an unscopedGITHUB_TOKEN. - Search for string interpolation of
github.event.*fields intorun:shell steps orgithub-scriptbodies. Branch names, PR titles, and comment bodies are all attacker-controlled text. Pass them throughenv:and reference the environment variable instead of splicing the expression directly into the command. - Trace what crosses from a fork-triggered workflow into a privileged one — via
actions/upload-artifact/download-artifact, step outputs, or files written to$GITHUB_ENV. A privileged workflow consuming that data has to re-validate it, not trust that the upstream job already did. - Pin
actions/checkoutto v7 (or confirm the July 20 backport applies) and audit everyallow-unsafe-pr-checkoutusage — that flag is the one place a team gets to declare "yes, we intentionally checked out untrusted code here," and it should be rare enough that every instance gets a name attached to it in review.
Nobody on this list — not Microsoft, not Google, not Cloudflare — treats CI security as an afterthought. They still shipped this. That's the actual lesson: this isn't a "hire better engineers" problem, it's a "the trust boundary is invisible in the YAML until someone specifically audits for it" problem, and it doesn't self-correct with scale or headcount.
Why this gets worse before it gets better
Novee's researchers flagged a specific accelerant: AI coding agents write CI/CD YAML fast, and they reproduce whatever pattern they were trained on — including the insecure ones — with no provenance signal attached to flag that a given pull_request_target block came from a template rather than a considered decision. A misconfiguration that used to take one engineer one mistake to introduce can now get stamped into dozens of repos in an afternoon by an agent generating boilerplate CI config on request, each copy looking exactly as confident and exactly as wrong as the last.
GitHub's own 2026 security roadmap is responding in kind — beyond the checkout v7 change, it lists a workflow lockfile that pins every direct and transitive Action dependency to a commit SHA, and "Workflow Execution Protections," centralized rulesets that control which events can trigger a workflow and who can trigger them at all. Both are aimed at the same target: making the trust boundary a policy the platform enforces, not a convention every workflow author has to remember correctly, every time, forever.
That's the same principle a self-hosted PaaS's own build pipeline should hold itself to. A tenant's git push triggers a build running on infrastructure the platform operates end-to-end — no third-party runner fleet, no CI vendor's own control plane sitting in the trust chain. That ownership doesn't grant immunity from Cordyceps-shaped bugs; it just means the audit checklist above is a platform team's job to run against its own release workflows, not a vendor's promise to take on faith.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, built and deployed through a pipeline the platform runs end-to-end. Star the repo on GitHub or deploy your first app today.
Sources:
- Cordyceps: The Silent Parasite Consuming Your Supply Chain — Novee Security
- Cordyceps CI/CD Flaws Expose 300+ GitHub Repositories to Supply-Chain Attacks — The Hacker News
- 'Cordyceps' CI/CD Flaw Exposes Microsoft, Google, Apache Repos to Pipeline Hijacking — Hackread
- Safer pull_request_target defaults for GitHub Actions checkout — GitHub Changelog
- Secure use reference — GitHub Docs.



