Your GitHub Actions workflows are green across the board. CodeQL found nothing. Your SAST tool gave you a clean bill of health. You're compliant, right?
Not according to Novee Security, which just flagged 654 repositories that passed every security scan but remained fully exploitable. More than 300 of those repos gave attackers direct access to secrets, credentials, and production systems.
This isn't a scanner bug. It's a fundamental misunderstanding of what CI/CD security actually means.
The Vulnerability: Cordyceps
Novee Security identified a class of vulnerabilities in GitHub Actions workflows they're calling Cordyceps. Like the fungus that hijacks an ant's nervous system, these vulnerabilities let attackers manipulate workflow logic to extract secrets that should never be accessible.
These workflows contain no malicious code. They pass static analysis and follow documented patterns. They look exactly like what you'd expect from a well-maintained repository.
The problem lies in how GitHub Actions handles workflow interactions, particularly around secret exposure and permission boundaries. An attacker can craft inputs that cause workflows to leak credentials during execution, even when those workflows appear secure in isolation.
Discovery and Impact
Novee Security discovered this vulnerability class during routine research into CI/CD platforms. They identified 654 affected repositories across major organizations.
Researchers verified exploitation paths in more than 300 repositories, meaning an attacker could gain unauthorized access without triggering any security alerts.
One confirmed case: Microsoft's Azure Sentinel repository. A stolen key from that repo provides persistent write access to security content used across Azure deployments. The workflow that exposed this key? It passed all standard security checks.
Failed Controls
Here's what went wrong:
Secret management boundaries: The affected workflows treated secrets as isolated variables, but GitHub Actions allows certain configurations to expose those secrets through log outputs, error messages, or artifact uploads. Your secret scanning tool checks for hardcoded credentials. It doesn't model how workflow execution contexts can leak runtime secrets.
Input validation at workflow boundaries: Workflows accept external inputs from pull requests, issue comments, and webhook payloads. When those inputs flow into commands or scripts without proper sanitization, they can manipulate the execution context. Your SAST tool checks the workflow file. It doesn't trace how untrusted input propagates through multi-step jobs.
Provenance verification: Many workflows pull actions from third-party repositories or use dynamically constructed action references. If you're not pinning actions to specific commit SHAs, you're trusting that the action's current version is the same one you reviewed. Scanner tools flag known-bad actions. They don't verify the supply chain integrity of every action in your dependency tree.
Permission scope creep: GitHub Actions allows workflows to request broad permissions (write access to repository contents, secrets access, package publishing). The default security posture assumes workflows are trustworthy. Scanners check for obviously excessive permissions. They don't model whether a workflow's actual behavior justifies its permission set.
Compliance Standards
PCI DSS v4.0.1 Requirement 6.4.3 states that custom scripts used in payment environments must be reviewed prior to deployment and protected from unauthorized changes. If your CI/CD pipeline deploys code to a cardholder data environment, these workflows are in scope. Passing a security scan doesn't satisfy "review prior to deployment" if the scan can't detect the vulnerability class.
ISO/IEC 27001:2022 Control 8.32 (change management) requires that changes to information processing facilities and systems are subject to formal change management procedures. Your GitHub Actions workflows are information processing facilities. If your change management process relies solely on automated scanning, you're not meeting the control's intent.
NIST 800-53 Rev 5 Control SA-10 (developer security testing) requires organizations to employ static and dynamic code analysis tools. Notice the word "employ," not "rely exclusively on." The control assumes you're using multiple verification methods, not treating scanner output as a binary pass/fail gate.
SOC 2 Type II CC6.1 (logical and physical access controls) requires that the entity implements logical access security measures to protect against threats from sources outside its system boundaries. Your CI/CD pipeline is a system boundary. If external inputs can manipulate workflow execution to extract secrets, you're failing this criterion.
Actionable Steps
Here's what you need to change:
Pin all actions to commit SHAs, not tags or branches. In every workflow file, replace uses: actions/checkout@v4 with uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab. Yes, it's uglier. Yes, it makes updates harder. That's the point. You're explicitly choosing which version of the action to trust.
Implement workflow-level permission minimization. Add explicit permission blocks to every workflow:
permissions:
contents: read
pull-requests: write
Start with the minimum set needed. Add permissions only when workflows fail with insufficient access errors.
Separate secret access from external input handling. If a workflow needs to process pull request data, it shouldn't also have access to production secrets. Use separate workflows: one that runs on pull_request events with no secret access, and another that runs on workflow_run after the first completes, with secrets but no direct access to untrusted input.
Audit your workflow execution logs manually. Pick your five most critical workflows. Run them with debug logging enabled (ACTIONS_STEP_DEBUG: true). Read every line of output. Look for secrets appearing in logs, error messages, or artifact paths. If you find any, that's a Cordyceps-class vulnerability your scanner missed.
Require manual approval for workflows that access secrets. GitHub allows you to require approval for workflows running on pull_request_target or workflow_dispatch events. Enable this for any workflow with write permissions or secret access. It's friction, but it's necessary friction.
Build a workflow provenance inventory. Document which workflows have access to which secrets, which external actions they depend on, and what their permission scope includes. Update this inventory as part of your change management process. If you can't answer "what could an attacker do with this workflow?" you don't understand your attack surface.
Your security scanners aren't useless. They catch a lot of problems. But they're checking syntax and known patterns. They're not modeling how your CI/CD system actually behaves under adversarial input. That's your job.



