Immutable releases on GitHub

Published 02.11.2025

I have an open source project which uses GitHub Releases as its binary distribution platform. I have a GitHub actions workflow which builds the Rust project using cargo, creates an installer and creates something called a “build provenance attestation”, which is a verifiable signature of the installer binary, created and managed by GitHub using SigStore. This can paired with a wordy GitHub CLI command such as gh attestation verify HeadsetBatteryIndicatorSetup.exe -o aarol on the downloaded binary to verify that the file on the releases page was actually created in the Actions workflow. This was, for a long time, the only way to verify that a binary was actually authentic.

Since the creation of GitHub Releases, maintainers have been able to freely edit releases after they have been published. A malicious maintainer could have replaced the assets of a release at any point with something dangerous, like infostealer malware. This was a serious supply chain risk that didn’t get that much attention until very recently.

Few projects have bothered to use attestations provided by the actions/attest-build-provenance@v3 action, and even fewer people actually bother (or even know about) verifying the binaries they have downloaded.

On October 28 of this year, GitHub announced that they have added a new feature, immutable releases! Basically, when a release is published as immutable, the assets in that release can no longer be added, modified or deleted. Git tags for immutable releases also can’t be deleted or moved, so you can’t replace a release with a new, malicious one.

The “Immutable” label on a release looks like this:

Screenshot showing where the immutable label is on a GitHub releases page

I’m very happy to see this change, since I can now confidently say that when you download my program, the code it runs is exactly the code you see in the repository.

Actually this is not completely true, since I’ve configured the GitHub action to create a release in “draft” mode first, where it is still completely mutable, so that I can add the changelog. Because of this, I’m probably going to put the release notes in a file in the repo so that the workflow can publish the release too.

Immutable releases can be enabled by simple checking a checkbox in the repo settings. I was initally surprised to see that the release I made a month ago was already labeled as immutable, but I guess it was because at some point I toggled the feature in the settings (but didn’t notice it since it didn’t have any effect in the UI).