Copyright (c) 2026 MindMesh Academy. All rights reserved. This content is proprietary and may not be reproduced or distributed without permission.

5.1.2. Immutable Actions and Version Pinning

💡 First Principle: Git tags are movable pointers, so @v3 has always been a promise rather than a guarantee — immutable actions replace that promise with a published, versioned package that cannot be altered after release, changing where an action is resolved from and what pinning means.

The old model resolved uses: owner/repo@ref by fetching that Git ref at run time. Because a maintainer (or anyone who compromises their account) can force-push a tag to point somewhere new, @v3 could silently become different code — the mechanism behind the widely-reported 2025 tj-actions/changed-files compromise, where a moved tag pushed credential-dumping code into thousands of workflows.

Immutable actions close that gap by publishing each release as an OCI package in GitHub Packages (ghcr.io) alongside the repository. Once published, that version's contents are frozen: the tag cannot be moved, and the version cannot be deleted and recreated with different bytes. Consumers keep writing uses: owner/action@v1.2.3 — the syntax doesn't change — but the reference now resolves to an immutable artifact rather than whatever a mutable ref currently points at. Publishing is done from a release workflow (GitHub's actions/publish-immutable-action), which requires semver-formatted tags and contents, packages, and id-token permissions, and the feature has been rolling out for actions consumed on GitHub-hosted runners.

The exam angle stated in the objectives is "implications for version pinning and registry sources," so hold three implications. First, SHA pinning remains the universally correct advice today for actions not published immutably — a full 40-character commit SHA is unforgeable regardless of tags (6.1.4). Second, immutability changes the release strategy: the long-standing practice of moving a v1 major tag to each new patch conflicts with a model where published versions are frozen, so maintainers publish new versions rather than re-pointing old ones. Third, the registry source matters — an action consumed as a package is subject to package-level permissions and visibility, which is why publishing needs packages: write.

⚠️ Exam Trap: Immutability is a property of the published version, not of the syntax you type. Writing @v1.2.3 against an ordinary Git-tag action gives you no immutability guarantee at all — the tag can still move. Don't confuse "looks precise" with "is pinned."

Reflection Question: Immutable actions and full-SHA pinning both defend against a moved tag. Name one thing each does that the other doesn't — one about readability, one about coverage of actions you don't control.

See how it connects
Alvin Varughese
Written byAlvin Varughese
Founder18 professional certifications