[HN Gopher] Immutable releases are now generally available on Gi...
       ___________________________________________________________________
        
       Immutable releases are now generally available on GitHub
        
       Author : fastest963
       Score  : 133 points
       Date   : 2025-10-31 13:59 UTC (9 hours ago)
        
 (HTM) web link (github.blog)
 (TXT) w3m dump (github.blog)
        
       | hoistbypetard wrote:
       | My instant reaction was: "Wait?! They weren't immutable before?"
       | 
       | I'm glad they're doing this, and it's an unpleasant surprise that
       | they didn't already work this way. I don't understand why they
       | allow mutable releases.
        
         | johnisgood wrote:
         | Yeah, how did it work before that it was not immutable?!
         | 
         | > With immutable releases, assets and tags are protected from
         | tampering after publication
         | 
         | I really, really wonder how it worked before. Can anyone
         | explain?
        
           | a022311 wrote:
           | "Before", it was trivial to move or delete tags and edit
           | release assets. The only stable identifier available was the
           | commit hash.
           | 
           | Immutable releases now enable permanently locking tags and
           | releases to make supply chain attacks harder to affect users
           | who are using release assets from before an attack occurred.
           | 
           | The previous behavior is still available by the way, I'm not
           | sure what you meant by "before".
        
             | johnisgood wrote:
             | > The previous behavior is still available by the way, I'm
             | not sure what you meant by "before".
             | 
             | I know, I was just wondering how it worked that needed this
             | improvement.
        
           | ItsHarper wrote:
           | Anyone with the appropriate perms could replace binaries
           | uploaded to the release at will. You could also change which
           | commit a release's tag pointed to by deleting and re-creating
           | the release (the link would end up the same since it just
           | references the tag).
        
           | danudey wrote:
           | 1. You could delete and re-create releases with the same name
           | 
           | 2. You could delete and re-create tags with the same name,
           | even if a release was pointing to that tag already
           | 
           | 3. You could delete and re-create an asset that was uploaded
           | to a release without doing any of the above.
           | 
           | By and large none of this is a problem on the surface, but
           | you could imagine someone who gains access to a project's
           | release credentials rebuilding a binary with a backdoor and
           | replacing the existing, published version in the release with
           | their new version after the fact.
           | 
           | An immutable release means that you could only inject that
           | code during the release process by injecting the backdoor
           | into the code itself, and since Github allows you to prevent
           | code from entering a branch except through an approved PR and
           | signed commits, it's possible to make that much more
           | difficult or impractical.
        
             | johnisgood wrote:
             | Thank you!
        
         | hk1337 wrote:
         | Git tags aren't even really immutable, they're treated as such
         | but they're not.
        
           | westurner wrote:
           | GitHub docs > Signing tags:
           | https://docs.github.com/en/authentication/managing-commit-
           | si... :
           | 
           | > _You can sign tags locally using GPG, SSH, or S /MIME_
           | $ git tag -s MYTAG -m "Signed tag"       # Creates a signed
           | tag            $ git tag -v MYTAG       # Verifies the signed
           | tag
           | 
           | Git book > 7.4 Git Tools - Signing Your Work: https://git-
           | scm.com/book/ms/v2/Git-Tools-Signing-Your-Work :
           | $ git commit -S -m 'Signed commit'
        
             | jayknight wrote:
             | But you can still delete and recreate/sign the same tag
             | again.
        
               | TingPing wrote:
               | But GitHub has the option to prevent this. Just like
               | branches.
        
               | westurner wrote:
               | Sigstore.dev supports revocation:
               | 
               | "Don't Panic: A Playbook for Handling Account Compromise
               | with Sigstore" (2022) https://blog.sigstore.dev/dont-
               | panic-a-playbook-for-handling...
               | 
               | "Why you can't use Sigstore without Sigstore" (2023)
               | https://blog.sigstore.dev/why-you-cant-use-sigstore-
               | without-... :
               | 
               | > Revocation in Sigstore. _A recent post on this blog
               | notes that signatures alone don't tell you whether to
               | trust an artifact; for that, you need a verification
               | policy. This verification policy is a much more natural
               | place to handle revocation than the identity layer; see
               | Don't Panic for an example. This allows us to avoid the
               | scalability problems of global revocation lists (see
               | CRLite for a discussion of these issues). The mantra here
               | is revoke artifacts, not keys._
               | 
               | Artifact Attestation > Verifying an artifact attestation
               | for binaries: https://docs.github.com/en/actions/how-
               | tos/secure-your-work/... :                 gh attestation
               | verify PATH/TO/YOUR/BUILD/ARTIFACT-BINARY -R
               | orgname/reponame
               | 
               | If it is not possible to retract/revoke releases then,
               | there again, the installer MUST verify against a signed
               | list of revoked releases
        
           | kimixa wrote:
           | Any "given" name/ID (IE anything but the full hash) in a
           | distributed VCS has to be mutable - without some single
           | central arbiter of truth it's simply impossible.
           | 
           | I'm honestly a little surprised people seem to think they
           | might be immutable - I guess maybe if people see "git" as
           | "Actually Github"?
        
         | GuestFAUniverse wrote:
         | +1
         | 
         | Nobody thought about mutable releases being utterly bad
         | _before_? Baffles me...
         | 
         | As bad as hardware vendors selling products with different
         | chips inside as the same model (hello Cisco -- at least in
         | former times; hello HP, formerly selling at least three
         | different, _incompatible_ laptop power supplies with the same
         | label).
         | 
         | Mutability: surprise, surprise, I'm not what you expected! --
         | maybe one of IT's worst ideas.
        
           | bluGill wrote:
           | Once in a while someone makes a mistake and it is helpful to
           | just fix it.
           | 
           | I've done it myself, create a release, upload it, download to
           | a different machine and discover it doesn't work there, so
           | fix and retest. Only after all those steps do I hit send on
           | the release announcement. This is a useful workflow
           | (particularly the first time you release when you don't even
           | know what you are doing).
           | 
           | So long as nobody abuses that mutable releases are a great
           | thing. However a tiny minority of people are not trustworthy
           | and so we are forced to take away a great things because of
           | that minority.
        
             | cortesoft wrote:
             | That is what '-1' and the like are for.
        
               | danudey wrote:
               | Depending on the project, doing a re-release with an
               | appended or updated version number might be a huge
               | hassle. For a small, single-binary program run by an
               | agile team it's pretty trivial to recall a release and
               | publish a replacement, but for larger open-source
               | projects with long, complex, release processes, paying
               | customers, external docs, etc., spending an entire new
               | day doing an entire new release to fix one typo in one
               | word in one file in one artifact is less practical than
               | just re-uploading the file and updating your SHA256SUMS.
        
               | cortesoft wrote:
               | In that case, it seems like immutable releases aren't
               | what that project wants. You don't HAVE to enable
               | immutable releases.
               | 
               | The ability to change a release is fundamentally
               | incompatible with immutable releases, by definition. You
               | can have one or the other, not both.
        
               | bluGill wrote:
               | immutable releases are not what anyone wants. A few bad
               | actors forced them on us.
        
           | embedding-shape wrote:
           | > Nobody thought about mutable releases being utterly bad
           | _before_? Baffles me...
           | 
           | Some of us been requesting it as a feature since 2016, just
           | because it wasn't implemented until now doesn't mean even
           | people inside GitHub hasn't thought about it.
        
             | LumielGR wrote:
             | It's funny they call it "adding a new layer of supply chain
             | security", when I reported it in August 2015 I got this
             | answer:
             | 
             | > Thanks for the submission. We have reviewed your report
             | and determined that it does not present a security risk.
             | Tags and releases are not directly associated. The author
             | lookup for a given release is done when that release is
             | created and not upon subsequent updates. I can see how that
             | could lead to some confusing behavior. I passed your
             | observations on to our developers to see if we would want
             | to change that behavior in the future. But, given that it
             | does not present a security risk, it is not eligible for
             | reward under the Bug Bounty program.
        
         | danudey wrote:
         | We've had a few issues in the past where a file wasn't updated
         | during the release process, requiring us to re-publish one
         | small change. It's not optimal, but given the nature of our
         | release process being long and complex it's a lot easier to fix
         | the asset in three minutes rather than spend an entire day re-
         | building and re-publishing an entire release, updating our
         | docs, etc. just because of one line in one file that wasn't
         | updated correctly.
        
           | hoistbypetard wrote:
           | I guess I'm just lucky, then, to have only dealt with release
           | processes where it's no big deal to do a bump from 5.0.0 to
           | 5.0.1 so I can address something like that. Some of them were
           | long and complex, but they were scripted to the point where
           | it was uniformly better to jump by a 0.0.1 than risk having
           | two different releases with the exact same version # in the
           | wild.
        
             | tuhgdetzhh wrote:
             | Yeah, depending on the size of the project you could end up
             | having thousands of users downloading and installing 5.0.0
             | and then complaining.
        
         | edflsafoiewq wrote:
         | Mutable releases are used for continuous/nightly builds.
        
           | jsiepkes wrote:
           | In Java with Maven these have a special suffix, "-SNAPSHOT".
           | So "1.0.0-SNAPSHOT". Releases, like "1.0.0" are immutable
           | once released. I always thought that was a pretty sane model.
        
       | bob1029 wrote:
       | I struggle to get excited about this sort of thing when the most
       | essential functions of GitHub are falling apart. Reviewing PRs
       | has somehow gotten even worse since the original react update.
       | 
       | I think the only thing that would fix this issue is for them to
       | lose 20%+ of their customers to a competitor. Something very
       | simple that can vacuum up the GHES migration archive and proceed
       | as if it were 2018 again.
       | 
       | I'd be willing to completely sacrifice actions, project boards,
       | copilot, et. al. if it meant I could have ultra fast views into
       | code, issues and pulls. I really see no reason the PR view cannot
       | be pre-rendered on the server when the branch is pushed each
       | time. This should be an instantaneous response at review time. I
       | don't care if it's 5 megabytes of diff - If my browser can handle
       | the react slop, it can certainly handle a big chunk of static
       | DOM.
        
         | lubujackson wrote:
         | If it happens, it would likely be fully integrated versioning
         | in some LLM product.
        
       | rhodey wrote:
       | I am glad for this feature
       | 
       | If I have anyone's attention there is something related I would
       | like to see
       | 
       | Please add a small thing which users can look for on the public:
       | repo/actions page
       | 
       | This small thing should let users know the action was run by
       | github like is default and not run on a custom / private action
       | runner
       | 
       | The private action runner feature makes sense but many projects
       | tell users to look to the github action history to trust that
       | tests A, B, C passed. If the github action ran on a private
       | action runner then you really cannot trust that what is in e.g.
       | run.yml actually ran
       | 
       | The attestation feature can be used to prove that an action was
       | run by github and not by private / custom but users need to
       | install the github cli to validate attestations and this is a
       | heavy ask when I think an addition icon on repo/actions page or a
       | diff icon color will do better
        
         | rhodey wrote:
         | I am seeing some docs now that suggest
         | 
         | > runs-on: [self-hosted, ...]
         | 
         | Must be added to run.yml to use custom / private action runners
         | 
         | I did not find these docs last time I looked and so my feature
         | request may be already fulfilled
         | 
         | If anyone wants to chime in to say that `runs-on` can be relied
         | on or not I would be grateful
        
       | eviks wrote:
       | Why is deletion not allowed, which supply chain attacks work by
       | deleting a release, not changing it to a malicious one?
        
         | hiccuphippo wrote:
         | I'd guess one MO is to delete a malicious package/url shortly
         | after releasing it to prevent researchers from getting to it.
        
           | eviks wrote:
           | So they wouldn't make a release immutable?
        
             | zamadatix wrote:
             | Which means the tainted release doesn't matter anymore to
             | those consumers worried about the immutable release
             | attestation anyways. If others are worried about that, they
             | should probably consume only attested immutable releases as
             | well.
             | 
             | I'd still bet the larger portion was it was just a
             | particularly easy path to preventing downgrade attacks or
             | the like though. Could always be more to it as well I'm not
             | thinking of, just feels likely.
        
         | yjftsjthsd-h wrote:
         | I assume they're doing the trivial workaround to prevent
         | renaming by way of delete and recreate?
        
           | eviks wrote:
           | Then you'd ban the recreation part?
        
         | darkamaul wrote:
         | I think the reason here is to prevent deletion that cause
         | upstream disruptions.
         | 
         | See the reasoning in the PEP 763 (not adopted )
         | 
         | https://peps.python.org/pep-0763/
        
           | eviks wrote:
           | Strange they haven't identified negative security
           | implications: if the owner notices the hack he can delete the
           | malicious release before the central authority, so this would
           | limit the blast radius (think there was a recent such issue
           | with npm where there was a delay between discovery (by the
           | author) and removal)
           | 
           | Otherwise yes, leftpad/coverup risk is a thing
        
         | kbolino wrote:
         | Deletion creates a hole. The hole can be filled by something
         | else. This is a form of mutation.
         | 
         | What you probably want instead is one-way revocation. You place
         | a permanent marker that says "do not use this release because
         | it is {broken, malicious, ...}".
        
           | eviks wrote:
           | No, you can make the whole immutable, that is if a tag in an
           | immutable repo was used and deleted, it can't be used again
        
             | kbolino wrote:
             | An "immutable hole" just sounds like a "revocation marker"
             | without an accompanying message, so I don't think we're
             | really asking for different things, here. Nevertheless,
             | ordinary tag deletion -- what git natively supports --
             | can't be supported directly.
        
               | eviks wrote:
               | The difference is the unavailability of content. For
               | example, you attach the wrong binary and want to avoid
               | confusion/mistaken downloads either manual or via tools
               | that don't support your markers, in the most direct way -
               | by deleting the binary from release. But you can't fix it
               | if you opted into the security benefits of no hidden
               | mutation
        
         | danudey wrote:
         | 1. A release turns out to contain an exploitable bug
         | 
         | 2. A release is published to fix the bug
         | 
         | 3. Someone malicious with access deletes the release
         | 
         | 4. Everyone downloading the "latest" version gets the
         | exploitable version until the developers notice and re-publish
         | again
         | 
         | I think about tools used in CI systems that are often re-
         | downloaded in each run, like `helm` or `kubectl` or `crane` for
         | example; if they're pinning a previous version they stay
         | exploitable, and if they're downloading the 'latest' from
         | Github then this switcheroo keeps them exploitable. Given that
         | a lot of emergency security releases come with disclosure
         | ("this is being released to resolve CVE-2025-12345") another 12
         | hours of exploitability can be critical.
        
           | eviks wrote:
           | Thanks, interesting scenario, but if you have access to
           | releases like that how is this easier vs just publishing a
           | release with an exploit and getting the same X hours before
           | you're discovered?
        
       | codethief wrote:
       | For a user is there an easy way to see in the UI whether a given
       | Github repo's releases are immutable?
        
         | jjice wrote:
         | > If a release is immutable, you will see " Immutable" below
         | the title on the release page.
         | 
         | https://docs.github.com/en/code-security/supply-chain-securi...
        
           | codethief wrote:
           | Wonderful, thank you!
        
       | IshKebab wrote:
       | Well I guess they're doing _something_ at least. I kind of
       | thought Github had moved to maintenance mode. Maybe we 'll get
       | stacked PRs one day?
        
       | raphinou wrote:
       | As I'm working on a signing scheme for release authentication,
       | this is a welcome news.
       | 
       | To alleviate the issue of mutable releases I had set up a mirror
       | of releases checksums to be able to detect releases alterations.
       | This is not needed anymore for immutable releases.
       | 
       | And automatically publishing checking of releases artifacts is
       | also a good recent change by GH: in that project mentioned above
       | I have developed a cli downloader checking the checksums of the
       | downloaded file [1], but to be useful, it required the project to
       | publish checksums, and the project to be mirrored. Now both of
       | these requirements are dropped and the tool is readily useful for
       | all GitHub immutable releases.
       | 
       | 1: https://github.com/asfaload/asfald/
        
       | shpx wrote:
       | Would've made more sense to add a grey "Edited" to edited
       | releases. Releases are not actually immutable, GitHub could
       | change them. I don't know why you need to use sciency words to
       | say "editing disabled".
        
         | NoahZuniga wrote:
         | They are immutable! The releases are signed with an attestation
         | from a trusted third party that Github can't forge! Also these
         | attestations are public and anyone can verify that the signing
         | third party isn't misbehaving.
         | 
         | > Release attestations let you verify that an artifact is
         | authentic and unchanged, even outside GitHub. Attestations use
         | the Sigstore bundle format, so you can easily verify releases
         | and assets using the GitHub CLI or integrate with any Sigstore-
         | compatible tooling to automate policy enforcement in your CI/CD
         | pipelines. For instructions on how to verify the integrity of a
         | release, see our docs on verifying the integrity of a release.
         | 
         | They are using Sigstore, which is pretty standard in this
         | space.
        
       | mlhpdx wrote:
       | I love the idea but I fear the implementation. I don't use GitHub
       | actions for builds and upload ancillary artifacts to releases. I
       | guess I know what will be my distraction today.
        
       | dare944 wrote:
       | > When you enable immutable releases, the following protections
       | are enforced: * Git tags cannot be moved or deleted; * Release
       | assets cannot be modified or deleted
       | 
       | On the face of it, this seems like a non-starter. If a particular
       | immutable release represents a danger to the consumer (extreme
       | example: the software contains a bug that could result in
       | physical injury) one must have the ability to retract that
       | release so that no further consumers of the software could be
       | affected by it. It makes sense that a retraction of an immutable
       | release should not be reversible in such a way that the release
       | could be recreated with different contents. But retractions must
       | be possible, for both ethical and legal reasons.
       | 
       | I would also argue that its not sufficient to simply apply a
       | blanket "deny all" access control to dangerous releases (assuming
       | such a mechanism exists), as this does not adequately convey the
       | deprecating nature of the change (and as a result, could
       | mistakenly be reversed in the future). Ideally the retraction
       | itself would be immutable such that once retracted the release is
       | inaccessible forever.
       | 
       | Now, it may be that all this is supported by the new feature; I
       | haven't had the chance to test it yet. But nothing in the
       | documentation makes this clear one way or another.
        
         | weinzierl wrote:
         | I think there are compelling reasons to support:
         | 
         | 1. Unremovable
         | 
         | 2. Uninstallable while keeping the data available
         | 
         | 3. Removing the release completely (while keeping an audit log
         | that this happened)
         | 
         | 1 is for use-cases where availability trumps security. I'd
         | argue this should never be the case but at the same time it is
         | how our world ticks by and large. Hard to take this away from
         | people.
         | 
         | 2 is for security, forensics and heritage but at the cost of
         | availability. Uninstallable could mean to only offer the
         | artifacts in an archive.
         | 
         | 3 must always be possible as a last resort for illegal content
         | that slipped through all previous safeguard layers.
        
           | matt_kantor wrote:
           | Your note on 3 brings up a good point: I'm sure that if
           | there's a DMCA takedown notice or somesuch that GitHub will
           | in fact delete your "immutable" release which "can't be
           | deleted".
        
       | josephcsible wrote:
       | This seems too strong to me, especially the prohibition on
       | deletion. Why couldn't they have instead just showed a record of
       | modifications to releases, and/or embedded a hash of the contents
       | in the URL to them?
        
       | skrrtww wrote:
       | Uh, does this apply to the autogenerated source code artifacts?
       | Those are famously not stable because they are generated on-
       | demand with `git archive`. The value of this feature is really
       | undermined if they don't also provide a source code download with
       | a stable hash.
        
       | OptionOfT wrote:
       | And yet I received an update from                       uses:
       | github/codeql-
       | action/init@8a06050a8c0348fb4738f28e0cfbb6727cf054ce # v4.31.2
       | 
       | to                       uses: github/codeql-
       | action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
       | 
       | So someone must've moved the tag, even though that release is
       | supposed to be immutable. https://github.com/github/codeql-
       | action/releases
        
         | fastest963 wrote:
         | That release isn't immutable
        
       | lrvick wrote:
       | Just remember the only truly immutable release is one signed by a
       | key the host does not have access to, or one where you pin a hash
       | locally at the point of consumption.
       | 
       | Microsoft does not have strict third party code review policies
       | internally, has been hit with supply chain attacks before, and
       | will be hit again. Consider this a nice to have feature, but give
       | it zero trust.
        
       ___________________________________________________________________
       (page generated 2025-10-31 23:01 UTC)