Repository navigation
Description
Summary
Six workflow steps across five workflows install the flux CLI by piping an unpinned remote script into a root shell: curl -fsSL https://fluxcd.io/install.sh | sudo bash (or the equivalent download-then-sudo bash with no checksum). Whatever fluxcd.io serves at that moment runs as root on the runner, unversioned and unverified, and several of the jobs that do this later hold registry credentials in the same job.
Occurrences on main
.github/workflows/build-main.yaml:68.github/workflows/build-release.yaml:114.github/workflows/nightly.yaml:58and:238.github/workflows/pull-requests.yaml:156and:334(download to a temp file, thensudo bashit, no checksum, so the same trust level as the pipe)
The build and finalize jobs in pull-requests.yaml log in to OCIR after this step, so an attacker-controlled install script would execute in a job that later holds a registry token. A seventh occurrence arrives with the fork e2e lane (#3262), which is what surfaced the pattern.
Why this is inconsistent with the repo's own discipline
Container images in these same workflows are digest-pinned, and actions are SHA-pinned. The flux binary is the one build input that arrives as "whatever the vendor's CDN serves right now, executed as root". The repository already treats a floating :latest image tag as a defect (#3578); a floating install script with root execution is the same class with a worse blast radius.
Fix shape
Pin a FLUX_VERSION and fetch the release binary for that version with a checksum, once, in a shared step or a small helper under hack/, and use it from all six places so the version cannot drift per-workflow. The fork e2e lane (#3262) already carries a pinned-flux pattern with a rationale comment, which can serve as the in-repo precedent once it lands.
Activity
lexfrei commentedon Sep 26, 2026
One of these installs does not need to exist at all. The per-package
buildjob in pull-requests.yaml installs flux with the comment "installer is built in finalize, but some package image targets shell out to flux". Among the package Makefiles onlypackages/core/installercallsflux, and the installer is not in the build matrix (hack/build-matrix.shleaves it out, finalize builds it). So that step can be dropped instead of pinned, which makes this issue one site smaller. The arm64 build jobs in #4505 copy the same step and can lose it too.ci(workflows): pin flux, yq and helm-unittest installs (cozystack#4645)