Skip to content

ci: flux CLI is installed by piping an unpinned remote script into a root shell, in six places #3619

Closed

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:58 and :238
  • .github/workflows/pull-requests.yaml:156 and :334 (download to a temp file, then sudo bash it, 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

  1. added
    kind/bugCategorizes issue or PR as related to a bug
    securitySecurity-related issues and features
    area/ciIssues or PRs related to CI workflows, GitHub Actions, automation
    on Aug 7, 2026
  2. added
    security/lowLow severity security finding
    triage/acceptedIndicates an issue is ready to be actively worked on
    priority/important-longtermImportant over the long term, but may not be staffed and/or may need multiple releases to complete
    and removed
    triage/needs-triageIndicates an issue needs triage by a maintainer
    on Sep 23, 2026
  3. lexfrei commented on Sep 26, 2026

    @lexfrei
    ContributorAuthor

    One of these installs does not need to exist at all. The per-package build job 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 only packages/core/installer calls flux, and the installer is not in the build matrix (hack/build-matrix.sh leaves 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.

  4. added a commit that references this issue on Oct 5, 2026
    9239555
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area/ciIssues or PRs related to CI workflows, GitHub Actions, automationkind/bugCategorizes issue or PR as related to a bugpriority/important-longtermImportant over the long term, but may not be staffed and/or may need multiple releases to completesecuritySecurity-related issues and featuressecurity/lowLow severity security findingtriage/acceptedIndicates an issue is ready to be actively worked on

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions