RC RANDOM CHAOS

Workflows are code, not config

CI workflow modification executes under repository trust. The control surface is the file. The boundary is the weakest identity allowed to merge.

· 7 min read

1. Opening position

A CI workflow is not a configuration file. It is code that executes with the trust level of the repository it lives in. The activity labelled “megalodon,” described as mass backdooring of GitHub repositories via CI workflows, targets that execution context. The vector is the system operating as designed.

CI systems run code defined in workflow files the moment those files are committed, merged, or triggered by an event the workflow subscribes to. The execution context holds the secrets, tokens, and write permissions granted to the workflow. Compromise of the workflow file is compromise of the trust boundary attached to it. The control surface is the file. The blast radius is whatever the workflow has been permitted to touch.

The response cannot be “patch the vulnerability.” The label implies a defect in the platform to be corrected. The mechanism in scope is authorized code execution introduced by an unauthorized author. The platform behaved as specified. The question is who was allowed to introduce the workflow change, and what the workflow was permitted to do once it ran.

2. What actually failed

The publicly described mechanism is mass backdooring of GitHub repositories via CI workflows. Beyond that, specifics of the “megalodon” activity referenced in this brief are not confirmed. Number of affected repositories, identity of the operator, dwell time, persistence model, and downstream targets are not confirmed in the facts provided. Treat the named campaign as a label, not a sourced specification.

What is observable from the stated mechanism is that CI workflow files were modified or introduced in a way that caused code execution under the trust of the affected repositories. Whether this occurred through compromised maintainer credentials, malicious pull requests merged into target branches, modification of reusable workflows consumed across multiple repositories, injection through dependency updates, or another path is not confirmed. The vector category is CI workflow modification. The specific entry method is not stated.

The output of that execution context is also not confirmed in detail. Workflows in scope can read repository and organisation secrets, publish artifacts, push commits, open pull requests, sign releases, and invoke external services using stored credentials. Which of these capabilities the activity exercised is not stated. The exposure is bounded by what each affected workflow was already permitted to do. There is no single uniform impact across the affected set. Each repository’s blast radius is defined by its own workflow permissions and secret scope.

3. Why it failed

Workflow files are stored alongside application source and reviewed under the same change-control rules. The file format reads as configuration. The execution behaviour is arbitrary command execution with credentials. When a control treats a high-trust execution surface as a configuration artifact, review intensity, approval thresholds, and access boundaries align to the wrong category. The boundary breaks at the point where a change to .github/workflows/ is accepted under standard code-review rules rather than privileged-change rules.

Identity is the boundary that should hold. A workflow change is a privileged change. The actor able to merge a modification to a workflow file is, in operational terms, the actor with whatever permissions that workflow holds, including every secret it reads. If the merging identity is a maintainer account without phishing-resistant authentication, a bot with broad write scope, or an automation that approves on a label or a passing check, the boundary is set at that weakest identity. Whether any of those conditions applied to the activity described is not confirmed.

Trust validation in CI is one-shot at merge time and not continuous at execution time. Once a workflow file is in the default branch, subsequent runs execute it without re-validating authorship, change provenance, or the authorisation of the modification. There is no runtime check that asks whether a given workflow should be permitted to read a given secret on a given trigger. If the system permits a workflow to execute, it executes. Control effectiveness depends entirely on what was rejected before merge, because nothing is rejected after. A control that only operates at one moment, against one identity, is not enforcing the trust boundary it is assumed to enforce.

4. Mechanism of Failure or Drift

The drift is categorical. A workflow file carries the syntax of configuration and the authority of code. Review controls calibrated to YAML parse correctness, lint passes, and field-level diff approval do not address the authority the file holds at execution. The reviewer evaluates a text change. The runner executes a credentialed actor. The gap between those two views is the failure surface, and it is present whether or not a specific campaign exploits it.

The drift compounds through reuse. Reusable workflows, composite actions, and called workflows extend the trust of one repository into another at execution time. A change to a centrally referenced workflow propagates without a corresponding review event in each consuming repository. The identity that controls the upstream definition controls downstream execution across every consumer pinned to a mutable reference. Whether the activity labelled megalodon exercised this propagation path is not confirmed. The mechanism is consistent with the documented behaviour of the platform and with mass distribution of a single change across many targets.

The drift extends to permission scope. The default token issued to a workflow inherits broad write capability unless explicitly narrowed. Secrets are scoped to the repository or organisation, not to the specific job, step, or commit hash that should be permitted to read them. There is no per-step capability ledger that validates whether a given line of workflow code is allowed to call a given external service with a given credential. Execution authority is granted at workflow scope and consumed at step scope. Closing that gap is not a default platform behaviour. It is operator-owned, and where the operator has not closed it, the gap defines the boundary.

5. Expansion into Parallel Pattern

The same mechanism appears in any system where a declarative artifact controls a privileged execution context and is reviewed under non-privileged change rules. Kubernetes manifests committed to a GitOps repository carry the same shape. The YAML reads as configuration. The reconciler applying it executes with whatever the manifest specifies, including pod specifications that mount service-account tokens, host paths, and node-level capabilities. A reviewer evaluating field changes against a schema does not evaluate the runtime authority granted. The actor permitted to merge the manifest is the actor permitted to run a pod with that authority on that cluster.

Infrastructure-as-code artifacts carry the same property. A Terraform diff displays resource attributes. The apply step assumes the credentials of the pipeline that runs it, and those credentials typically hold broad authority over the target environment. Approval flows that gate on plan output, rather than on the identity of the proposer and the sensitivity of the resource set being changed, set the boundary at the weakest identity that can land a plan. The control surface is the file. The authority is the pipeline. The mismatch is identical to the CI workflow case.

Database migration runners follow the same pattern. A migration file is committed as code. The runner executes it with credentials that exceed application runtime credentials by design, because schema change requires schema authority. Review intensity calibrated to SQL correctness does not match the authority being exercised. In each of these cases the mechanism is the same: a declarative artifact, reviewed under standard rules, that triggers execution under privileged credentials in a context that does not re-validate the change at execution time. CI workflow modification is one instance of this pattern, not a special case.

6. Hard Closing Truth

A workflow change is a privileged change. The control set must treat it as such, or accept that the trust boundary is set at the weakest identity authorised to merge to the default branch. Code-owner enforcement on .github/workflows/ paths, phishing-resistant authentication on every account in that owner set, and required review by an identity distinct from the proposer are the minimum conditions for the boundary to hold. Whether any of these were present or absent in the affected repositories is not confirmed. The structural point holds regardless of the campaign-specific facts.

Workflow token permissions must be reduced to the minimum required by each job. Repository and organisation secrets must be scoped to the specific workflows, environments, and branch contexts that require them. Environment protection rules, required reviewers on deployment environments, pinned action references by commit SHA, and OIDC-federated short-lived credentials in place of long-lived secrets reduce the value of compromising any single workflow file. Where these are not configured, the workflow holds the full delegated authority of the repository, and compromise of the file is compromise of that authority in full.

Detection at execution time is the final containment. Audit logging on workflow file modifications, alerting on changes to reusable workflows and action pins, runtime egress controls on self-hosted runners, and reconciliation of published artifacts and releases against an out-of-band record of authorised builds are the controls that operate after merge. The CI platform will execute what it is instructed to execute. If the control set depends on the merge gate alone, the boundary is one identity wide. Identity is the boundary. Workflows are code. Trust must be validated at execution, not assumed from a prior review.

Share

Keep Reading

Stay in the loop

New writing delivered when it's ready. No schedule, no spam.