# Mutable action tag repointing

Actions pinned to tags or branches instead of full commit SHAs, letting a force-push run attacker code

_Area: Software supply chain and CI/CD. Seen in 7 disclosed reports; latest 2026-07-01. Updated 2026-10-23._

## How it works
A reference like `owner/action@v1` names a tag, not code. Tags and branches are mutable: anyone with push rights can force-push the tag to any commit in the object store, including a commit that never lands on a branch. Consumers who pin to the tag run whatever it points at when their workflow executes, with the workflow's secrets and runner memory in reach [E1](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-teampcp-attack-kics-github-action.md)[E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md)[E3](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-supply-chain-compromise-codfish-semantic-release-action.md). The broken assumption is that `@v1` identifies reviewed code; it only identifies a name.

## Where it shows up
- `uses:` lines with `@v1`, `@v5`, `@main`, or any tag/branch rather than a full 40-character SHA.
- Tags whose commit is not reachable from any branch ("does not belong to any branch" banner) [E3](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-supply-chain-compromise-codfish-semantic-release-action.md)[E5](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md)[E6](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-actions-cool-issues-helper-github-action-compromised-all-tags-point-to-imposter-commit-that-exfiltr.md)[E7](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-xygeni-action-compromised-c2-reverse-shell-backdoor-injected-via-tag-poisoning.md).
- Low-profile setup/install actions pulled in transitively by popular actions [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md).
- Entrypoint scripts (`install.sh`, `entrypoint.sh`, `action.yaml`) changed without a corresponding branch commit [E1](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-teampcp-attack-kics-github-action.md)[E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md)[E5](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md).
- Mass tag rewrites: every tag in a repo or org showing a fresh creation time and identical fake author [E1](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-teampcp-attack-kics-github-action.md)[E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-laravel-lang-supply-chain-attack.md)[E6](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-actions-cool-issues-helper-github-action-compromised-all-tags-point-to-imposter-commit-that-exfiltr.md).
- Composer packages whose `composer.json` gains an `autoload.files` entry pointing at a new helper [E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-laravel-lang-supply-chain-attack.md).

## How to review
The invariant: every third-party action reference must resolve to an immutable commit SHA that matches the reviewed release and is reachable from a branch. Check each `uses:` for a full SHA; flag tags and branches. For each tag in use, confirm its commit is on a branch and diff it against the legitimate HEAD of the default branch. Treat transitive action dependencies as first-class: enumerate what your actions call [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md). As monitoring (not a review gate), baseline egress per workflow step and alert on new destinations, especially typosquats [E5](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md).

## Variants seen
- Force-push of a major tag (`v1`) on a setup action to a fork commit that dumps runner memory [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md).
- Mass repointing of all tags across related actions to imposter commits with a credential stealer [E1](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-teampcp-attack-kics-github-action.md)[E6](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-actions-cool-issues-helper-github-action-compromised-all-tags-point-to-imposter-commit-that-exfiltr.md).
- Lightweight tag (`v5`) moved to a backdoored unmerged commit via stolen maintainer/App credentials [E7](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-xygeni-action-compromised-c2-reverse-shell-backdoor-injected-via-tag-poisoning.md).
- Every tag across multiple Composer packages rewritten to add an autoload dropper [E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-laravel-lang-supply-chain-attack.md).
- Repointed tags plus a malicious release binary in the same project [E5](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md).

## Why fixes fail
Containment after a prior PAT theft was incomplete, so the attacker returned and repointed tags a second time [E5](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md). Rotating credentials without re-pinning consumers leaves the mutable reference in place. Attackers also made tags immutable via Repository Rulesets to block recovery [E3](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-supply-chain-compromise-codfish-semantic-release-action.md).

## Impact and severity
High: leaked workflow secrets and PATs, which unlocked more popular downstream actions [E2](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md), exfiltrated CI secrets to attacker infrastructure [E1](https://bugbountylibrary.com/r/blog%3Awiz-io-blog-teampcp-attack-kics-github-action.md)[E4](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-laravel-lang-supply-chain-attack.md)[E5](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md)[E6](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-actions-cool-issues-helper-github-action-compromised-all-tags-point-to-imposter-commit-that-exfiltr.md), and a C2 backdoor reaching all tag consumers [E7](https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-xygeni-action-compromised-c2-reverse-shell-backdoor-injected-via-tag-poisoning.md). Severity rises with tag popularity, secret scope, and transitive reach.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Awiz-io-blog-teampcp-attack-kics-github-action.md
- E2: https://bugbountylibrary.com/r/blog%3Awiz-io-blog-new-github-action-supply-chain-attack-reviewdog-action-setup.md
- E3: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-supply-chain-compromise-codfish-semantic-release-action.md
- E4: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-laravel-lang-supply-chain-attack.md
- E5: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-trivy-compromised-a-second-time-malicious-v0-69-4-release.md
- E6: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-actions-cool-issues-helper-github-action-compromised-all-tags-point-to-imposter-commit-that-exfiltr.md
- E7: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-xygeni-action-compromised-c2-reverse-shell-backdoor-injected-via-tag-poisoning.md
