Last week, a security research firm called Novee quietly dropped findings that should make every team running GitHub Actions stop what they are doing and audit their workflows. They named the vulnerability class Cordyceps — after the parasitic fungus that hijacks its host from the inside — and it is an apt metaphor. The bug does not attack from the outside. It lives inside your own CI/CD pipelines, waiting for someone to open a pull request.
After scanning roughly 30,000 high-impact open-source repositories, Novee validated over 300 fully exploitable attack chains. The affected organizations include Microsoft, Google, Apache, Cloudflare, and the Python Software Foundation. The researchers confirmed that a free, anonymous GitHub account is sufficient to steal non-expiring credentials, push malicious code, or assume owner-level permissions on cloud infrastructure — no organization membership required.
What Cordyceps Actually Is
Cordyceps is not a single CVE. It is a class of vulnerabilities — a pattern that keeps appearing across GitHub Actions workflows because of a fundamental misunderstanding about what workflow YAML files actually are. Most engineers treat them as configuration. They are not. They are executable code that runs with repository maintainer permissions, and they accept input from the public internet.
The attack surface is any place where untrusted external input — a PR title, a branch name, a PR comment — gets interpolated into a shell command or evaluated in JavaScript inside a workflow step. When that happens, an attacker can craft that input to execute arbitrary code in your CI environment, with all the permissions that environment carries.
Novee identified four distinct vulnerability categories within Cordyceps:
- Command injection: Branch names or PR titles interpolated directly into shell commands — for example,
run: echo "Branch: ${{ github.event.pull_request.head.ref }}"wherehead.refis attacker-controlled. - Code injection: Untrusted input flowing into
actions/github-scriptwhere it gets evaluated as JavaScript. - Broken authorization: Not missing permission checks, but logic bugs in the checks that do exist — conditions that can be bypassed with carefully shaped input.
- Cross-workflow escalation: The most dangerous pattern. A low-privilege workflow writes an artifact or environment variable that a high-privilege workflow later reads. The exploit chain is invisible when you look at either file in isolation.
That last category is what defeats traditional security tooling. SAST scanners work on single files. The most severe Cordyceps exploits span multiple workflows, and the trust boundary violation only becomes visible when you trace data flow across the entire execution graph. As The Hacker News reported, existing tools simply cannot reason about a cross-workflow finding.
What They Found at Major Organizations
The specific findings are sobering. This is not theoretical.
On Microsoft's Azure Sentinel repository, Novee found that a comment on a pull request could trigger code execution on Microsoft's CI runners and exfiltrate a non-expiring GitHub App key. Azure Sentinel distributes security detection rules to enterprise customers globally. An attacker with persistent write access to that repository does not just own a GitHub repo — they own the security posture of every organization pulling those rules downstream.
On Google's AI Agent Development Kit, a single pull request was sufficient to execute attacker-controlled code on Google's CI and claim roles/owner on the associated Google Cloud project. In GCP terms, that is the highest privilege level available — full administrative control over every resource in the project.
At Apache Doris, researchers found two independent attack paths: a comment-based credential exfiltration route and a fork PR token theft. Apache Doris has over 10,000 enterprise users. Either path gave an attacker the ability to modify the source code those users would eventually compile and ship.
Cloudflare's Workers SDK was vulnerable to arbitrary command execution via crafted branch names. The Python Software Foundation's Black formatter — which ships in Docker images downloaded 130 million times per month — had an exploitable path to steal bot automation tokens, giving an attacker the ability to approve pull requests without human review.
Microsoft and Google confirmed impact. According to Dark Reading, Apache, Cloudflare, and the Python Software Foundation have since applied patches. But Novee only scanned 30,000 of the most prominent repositories. The same patterns almost certainly exist in the millions of private organizational repositories running GitHub Actions today.
Why AI Coding Tools Are Making This Worse
Here is the part of this story I cannot stop thinking about. Novee noted in their root cause analysis that AI coding agents are reproducing these vulnerable patterns at scale — and that observation deserves more attention than it has received.
When a developer asks Cursor, Claude Code, or GitHub Copilot to generate a GitHub Actions workflow, those tools draw on patterns in their training data. And the training data contains millions of vulnerable workflows, because the vulnerable patterns have been endemic for years. The insecure interpolation of ${{ github.event.pull_request.title }} into shell commands was never flagged as dangerous by most linters, so it propagated freely across open-source repositories without anyone raising a flag.
AI assistants generate syntactically correct, functionally reasonable workflows that happen to be exploitable. They do it at a speed and scale no human review process is designed to catch. Every new repository spun up by an AI-assisted developer is a potential Cordyceps host — the vulnerability persists and spreads not because people are careless, but because the pattern looks safe to everyone reviewing it, including the tools doing the reviewing.
I have been running infrastructure for a long time. The hard lesson is that every system executing code on behalf of external input is an attack surface, no matter how it looks in the editor. CI/CD pipelines are particularly dangerous because they sit at the intersection of maximum privilege and maximum external trust: they pull from GitHub, push to registries, deploy to cloud accounts, and they do it automatically. That combination leaves almost no room for the kind of input validation we would demand anywhere else in the stack.
What You Should Do Right Now
Start with your most privileged workflows — the ones that deploy to production, push to container registries, or interact with cloud credentials. For each one, ask: where does external input enter this workflow? That means PR titles, branch names, commit messages, PR comments, and anything in github.event that an external user can control.
- Never interpolate
${{ github.event.* }}directly intorun:blocks. Pass external values as environment variables and reference them with shell variable syntax, which does not evaluate the same way. - Audit every use of
pull_request_target. This trigger runs with write permissions even on PRs from forks. It requires explicit sanitization of every external input it touches. - Map your cross-workflow data flows. Identify every place where one workflow writes an artifact, cache entry, or environment variable that another workflow reads. Each of those handoffs is a potential trust boundary violation.
- Restrict permissions at the job level. Use
permissions:blocks in your workflow YAML to grant the minimum required scopes. Default GitHub Actions permissions are broader than most teams realize. - Treat workflow YAML as code in your review process. Require the same security-aware review for workflow changes that you would require for authentication code or infrastructure configuration.
Novee has published their full technical write-up at novee.security/blog/cordyceps. It is detailed and worth reading with your team. SecurityWeek also has solid coverage of the broader scope — millions of repositories likely carry the same patterns.
The Bigger Picture
What bothers me most about Cordyceps is not the specific vulnerabilities — those are fixable. It is the category error that produced them: treating workflow files as configuration rather than code. We have been down this road before. Shell scripts were just scripts. Dockerfiles were just build instructions. Infrastructure-as-code was just config. Every time we treat executable logic as benign configuration, attackers find a way to remind us that execution is execution.
GitHub Actions workflows run on real compute with real credentials making real changes to real systems. They pull secrets from vault. They push images to registries. They deploy to production Kubernetes clusters. They are code. They have a security posture. They need to be reviewed, tested, and hardened accordingly.
The organizations hit by Cordyceps are not careless. Microsoft, Google, Apache — these are teams with serious security programs and mature engineering cultures. The issue is systemic, and it was invisible to conventional tooling because conventional tooling was not designed to trace trust boundaries across workflow execution graphs. That is exactly the kind of problem that spreads unchecked until someone publishes a name and a proof of concept. Novee did the work. Now it is on the rest of us to act on it.