Skip to content

Turn on immutable GitHub releases for this project #914

Description

@connorshea

Hello! Given the recent attacks on GitHub Actions where credentials were compromised and then tags got overwritten (e.g. this one from today), it would be a good idea to turn on immutable releases for the Git tags in this repo to prevent that kind of attack from hitting this repo: https://docs.github.com/en/code-security/concepts/supply-chain-security/immutable-releases

This wouldn't fix the problem entirely and would not protect someone using ruby/setup-ruby@v1 if an attacker published a new, malicious v1.x release, but it'd at least help protect some users in some cases for minimal work (e.g. if they had ruby/setup-ruby@v1.310.0 and that tag was immutable, they'd be safe).

Unfortunately you can't turn on immutable releases retroactively without un-publishing and re-publishing existing releases, but we can at least ensure that all future releases are immutable 🤷‍♂️

Activity

  1. ntkme commented on May 19, 2026

    @ntkme
    Collaborator

    As you already mentioned, immutable releases do not solve much of the security problem when write access is leaked.

    As for end users who have concerns over immutability of changes, our recommendation is always to lock the github actions at specific git commit sha, instead of git branch or tag. For example:

    https://github.com/ruby/rubygems/blob/7a326f540448ca3cfd7a6a897c29403a2b8b2417/.github/workflows/rubygems.yml#L60

    Note:

    1. Dependabot supports updating git commit sha for actions, so you can still get updates this way as usual.
    2. sha256 collision attack is theoretically possible, but realistically not possible anytime soon.
  2. hakusaro commented on May 19, 2026

    @hakusaro

    As you already mentioned, immutable releases do not solve much of the security problem when write access is leaked.

    It does, because if write access is leaked you still cannot republish an existing tag.

  3. ntkme commented on May 19, 2026

    @ntkme
    Collaborator

    This wouldn't fix the problem entirely and would not protect someone using ruby/setup-ruby@v1 if an attacker published a new, malicious v1.x release

    You can read the security recommendations from GitHub: https://docs.github.com/en/actions/reference/security/secure-use#using-third-party-actions

    They also recommended “pin actions to a full-length commit SHA” as a stronger security measure than “pin actions to a tag.” Whether a tag is immutable or not is irrelevant when pinning by SHA.

    You may also want to read discussions in regarding this topic, that the scope of immutable releases for this project is way larger than you would think as this project use binaries from multiple other repositories: #848

  4. eregon commented on May 19, 2026

    @eregon
    Member

    Using immutable releases for ruby/setup-ruby releases itself would probably be easy, but indeed it doesn't achieve much.

    https://github.com/ruby/ruby-builder is where immutable releases would matter, but then that gets in the way of legitimately rebuilding a release (rare to be fair, but it has happened that a build succeeded yet the Ruby was broken so we had to rebuild it, compilation is not always deterministic) and adding new platforms when they become available. It's in theory possible to find ways around that but it sounds very complicated and inconvenient.

    If someone gets write access though, can't they publish new immutable releases (of either repository)?
    If so, what have we gained security-wise?

    It does, because if write access is leaked you still cannot republish an existing tag.

    This is already prevented, tags are immutable for this repository, i.e. they can't be updated, deleted or force-pushed by anyone, via a Ruleset.

  5. ntkme commented on May 20, 2026

    @ntkme
    Collaborator

    https://github.com/ruby/ruby-builder is where immutable releases would matter

    In addition, we have these dependencies where immutable releases would matter for ruby on windows:

    setup-msys2-gcc would be the most challenging one to achieve true immutability, as right now we check for update every day and it publishes new releases a few times every week. setup-ruby always consumes the latest release of setup-msys2-gcc. It means that if we want to achieve immutability, we would have to switch to specific release tags, and create a new release for setup-ruby every time we update setup-msys2-gcc. It would be extremely noisy to the end users with hundreds of immutable releases per year.

    Turning on immutable releases is one thing, how to effectively use immutable releases is another thing - we can easily enable immutable releases for setup-msys2-gcc, but as long as setup-ruby continue to use latest, it does not make anything better in terms of security as hacker may just publish a new latest compromised immutable release.

  6. hakusaro commented on May 20, 2026

    @hakusaro

    This is already prevented, tags are immutable for this repository, i.e. they can't be updated, deleted or force-pushed by anyone, via a Ruleset.

    If a contributor with the ability to change rules is compromised, changing the ruleset is trivial.

  7. eregon commented on May 20, 2026

    @eregon
    Member

    If a contributor with the ability to change rules is compromised, changing the ruleset is trivial.

    In such a case (which requires admin access AFAIK), isn't it also trivial to disable immutable releases?
    Existing releases would still be immutable, but new releases wouldn't be.

    I think the bottom line is if an attacker gains write access, they could make a new release (whether immutable or not) and that's not helped by immutable releases, isn't it?

  8. Chrimle commented on Jul 23, 2026

    @Chrimle

    In such a case (which requires admin access AFAIK), isn't it also trivial to disable immutable releases? Existing releases would still be immutable, but new releases wouldn't be.

    Once a release is published as immutable, it cannot be mutated. Even when disabling the setting. The setting applies to new releases, not existing ones.

    I agree with the SHA-pinning though, it's best practice for the downstream. But I think the intention of this issue, was applying best practices on the upstream.

  9. ntkme commented on Jul 23, 2026

    @ntkme
    Collaborator

    But I think the intention of this issue, was applying best practices on the upstream.

    Again, my reason against at least for now is that too many people simply connect "immutable" directly to "safety," without knowing that there are mutable pieces the "immutable release" could load dynamically at runtime, that an immutable release here today would not be fully immutable, and would still have potential attack surfaces in theory.

    "Best" practice is not always the best. In this case, the "best practice" of immutable release would lead to a false sense of security - one of the commonly overlooked threats. Without any efforts of making the whole supply chain around this project immutable, there isn't any real value other than signaling that "best practice" is being applied when it's not really applied.

  10. Chrimle commented on Jul 23, 2026

    @Chrimle

    Immutable has nothing to do with the project, source files, dependencies, and has nothing to do with determinism nor purity. Immutable in this context, applies to the releases and associated tags. The fact that they cannot be modified once published. Just because there are transitive dependencies, means nothing, regardless of how mutable those may be.

    I understand what @eregon meant by "sometimes it doesn't build, and it needs to be retried", I've been there. But consider this; IF something would be a target, it's definitely this action. It's the last one in the chain, and it's the one that gets published to the marketplace instantaneously.

    If a Repo-admin got compromised, it would be trivial to update the release, and stealthily republish compromised code to the marketplace - which, unless you use SHA-pinning, you would start using when a new GitHub Action is triggered - without you making a code change, and without your awareness.

    There is a reason why GitHub actions caused major vulnerabilities to be spread near-uncontrollably, and there is a reason for why GitHub added immutable releases, and immutable git tags.

    When this project gets compromised, it shouldn't be the responsibility for down-streams to use SHA-pinning. But I understand that making an immutable release containing a latest-reference, sounds... counter-intuitive. But that's a separate discussion, is it not? I mean, the release of this project, is the source-code of this project. Perhaps it would give a false sense of security, if all it is, is a wrapper around a dynamic external dependency.

    I agree, it's rather "Less Bad" Practices. As long as considerations are taken, that's what's important - regardless of action (or inaction). 😉 Good discussions!

  11. eregon commented on Jul 23, 2026

    @eregon
    Member

    Perhaps it would give a false sense of security, if all it is, is a wrapper around a dynamic external dependency.

    It is basically that, it downloads builds from https://github.com/ruby/ruby-builder/releases.
    So I think you are almost agreeing immutable releases of ruby/setup-ruby would give a false sense of security.

    One motivation to do this would be to make it a bit safer for usages which don't do sha pinning (which use setup-ruby@v1).
    But I don't think it makes that any safer in practice, because immutable releases doesn't prevent an attacker with write access to just create a new immutable release.

    The only advantage then seems for setup-ruby@v1.2.3 usages, which seem extermely rare and a bad security/convenience trade-off as detailed above.

    I'll close this, we seem to have clearly established that just using immutable releases only gives a false sense of security.

    Making ruby-builder releases immutable would enhance security but also seems a hugely complicated project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions