Your CI pipeline is green. All checks passed. The dashboard looks clean.
That means nothing if you’re using GitHub Actions in certain ways.
In June, researchers at Novee Security disclosed a CI/CD weakness they named Cordyceps. They scanned about 30,000 high-impact repos across npm, PyPI, crates.io, and Go — flagged 654, confirmed over 300 as fully exploitable. The affected tooling included projects from Microsoft, Google, Apache, Cloudflare, and the Python Software Foundation.
The entry requirement for an attacker? A free GitHub account. No org membership. No special access.
The vulnerability isn’t in any single file. It’s in the composition. The problem starts with pull_request_target and workflow_run triggers — they run in the base repository’s context with access to secrets. An attacker can trick both by putting malicious content in a pull request. GitHub Security Lab calls this the pwn request.
Three primitives do the damage. Command injection lets attacker-controlled data land unescaped in a shell. Code injection through actions/github-script evaluates attacker input as JavaScript at runtime. Cross-workflow privilege escalation lets a low-privilege workflow write data that a high-privilege workflow reads and acts on with the maintainer’s token.
No single workflow is vulnerable alone. The danger is how they connect. That’s exactly why your scanners miss it — SAST and DAST tools check one file at a time, and every YAML file here is valid, well-formed, doing what it was told.
On Microsoft’s Azure Sentinel repo, a comment on a pull request could run attacker code on Microsoft’s CI and steal a non-expiring GitHub App key — confirmed by MSRC. On Google’s AI Agent Development Kit, a single PR could escalate to owner-level access on the associated Google Cloud project. Apache Doris had a similar path.
Novee found no evidence of exploitation in the wild. But this is a proven, exploitable pattern, and it’s largely unpatched by default across the industry.
The fixes: prefer pull_request over pull_request_target. Never check out PR head code in a privileged workflow. Pin third-party actions to a commit SHA. Set default permissions to read-only. Gate privileged workflows behind manual approval.
