The Supply Chain Risk Between CI Workflows

Cordyceps is a useful reminder that some CI/CD risks do not live in one workflow file. They live in the trust boundary between workflows.

The Supply Chain Risk Between CI Workflows

A green CI pipeline can still be a badly governed one. That sentence sounds uncomfortable, but the recent Cordyceps research made it very concrete.

Novee Security described a class of CI/CD weaknesses where an attacker does not need repository membership, maintainer rights, or a leaked token to start the chain. A free account and a pull request can be enough if the workflow design crosses the wrong trust boundary. BleepingComputer summarized the same point well: many scanners stay green because they look at one workflow file at a time.

That is the part I care about most. This is not only a GitHub Actions problem. It is a measurement problem.

The Bug Is Not Always In One File

Most CI security checks are still shaped like file scanners. They inspect a workflow. They look for risky commands, unpinned actions, broad permissions, direct secret exposure, or suspicious shell patterns. That work matters. It catches real problems.

But Cordyceps points at a different failure mode. A low-privilege workflow can run on untrusted pull request input and produce an artifact. A second workflow can later run with higher privileges, download that artifact, and act on it with secrets or a write-capable token in scope.

Look at each workflow alone and the danger can disappear. The producer is just building or uploading output. The consumer is just downloading and processing an artifact. Neither file needs to contain one obviously malicious line. The vulnerability lives in the connection.

That is why the phrase “workflow code is code” is true, but incomplete. Workflow composition is architecture. Architecture has trust boundaries. Trust boundaries need review.

Why This Gets Worse With AI-Generated CI

I am not against AI-assisted development. The productivity gain is real. But CI/CD configuration is a place where small mistakes can create very large authority shifts.

An agent can generate a workflow that looks reasonable: run tests on pull requests, upload results, comment back with a report, trigger a follow-up job after completion. Each step sounds useful. The problem starts when untrusted data from the first step becomes trusted input for the second step.

Humans already miss this kind of boundary. AI makes the volume problem harder. It can produce more workflow decisions than a review process was designed to absorb. If the review only asks “does this YAML look normal?”, it will miss the question that matters: “who controlled this data before this privileged workflow consumed it?”

What We Changed In supply-chain-guard

This is the reason I like the v5.7.0 change in supply-chain-guard. It does not treat Cordyceps as an IOC problem. There is no domain list or hash feed that solves this class. The useful detection is structural.

The new GitHub Actions analysis is trigger-aware. It understands workflows that run in privileged contexts, including pull_request_target, workflow_run, issue_comment, and similar event paths. It also checks for the classic pwn request pattern: a privileged workflow that checks out attacker-controlled pull request code and then runs it.

The bigger change is the cross-workflow graph. supply-chain-guard now models producer and consumer workflows across the repository. It can flag a case where an untrusted pull request workflow uploads an artifact and a privileged workflow_run consumer downloads it later. If the consumer executes downloaded content, the finding becomes critical. If it consumes the artifact with secrets or a write token in scope, that is still a trust-boundary risk.

That matters because a single-file scanner can miss the exact attack class. A graph can ask the better question: where did this artifact come from, who controlled it, and what authority exists when it is consumed?

The Practical Takeaway

The immediate fixes are not exotic. Prefer unprivileged pull_request workflows for untrusted contributions. Avoid checking out pull request head code inside privileged workflows. Keep default token permissions narrow. Treat issue comments, pull request titles, branch names, labels, and artifact contents as attacker-controlled input. Do not inline that data into shell commands or JavaScript execution.

But the longer-term fix is about how we review CI/CD. We need to stop treating workflow files as harmless configuration. They run commands, move artifacts, hold credentials, publish releases, and decide what gets trusted downstream.

So the review model has to change from “scan every file” to “understand the pipeline.” Which event triggered this workflow? Which token does it get? Which secrets are present? Which artifacts or outputs cross from untrusted to privileged context? Which step executes data that came from outside the trust boundary?

That is a different kind of security question. It is closer to threat modeling than grep.

What I Would Check First

If I had to review a repository quickly, I would start with workflows using pull_request_target, workflow_run, issue_comment, and any job with broad write permissions. Then I would trace artifact uploads and downloads across workflow files. I would look for actions/github-script blocks that evaluate event data, shell commands that interpolate pull request metadata, and consumers that run downloaded content.

I would also pay attention to successful pipelines. A green check tells me the automation completed. It does not prove the trust model is sound.

That is the real lesson from Cordyceps for me. Supply-chain security is not only about finding malicious packages after someone publishes them. It is also about stopping our own automation from becoming the authority an attacker borrows.

A pipeline can be green and still be wrong. The hard part is teaching our tools to see why.

References

Novee Security’s Cordyceps research

BleepingComputer’s coverage of the attack pattern

supply-chain-guard v5.7.0 changelog