Tags are not immutable
ID |
tag_protection |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Family |
SCM |
Tags |
ASVS50:v15.1.1, cicd-sec-09, cicd-security, security, source-code, spvs10-v3.3.18, supply-chain, tag-protection |
Description
Are the repository’s tags protected against being moved or deleted?
A release tag is a trust anchor: consumers pin a GitHub Action or a download to a tag (for example uses: org/action@v1) and assume the tag keeps pointing at the reviewed commit. GitHub tags are mutable by default — a tag can be re-pointed to a different commit or deleted and recreated. The check fetches the repository’s actual tags and reports the ones not covered by an active GitHub ruleset that restricts both tag update and tag deletion.
| Tag rulesets are a GitHub-native primitive, so this detector applies to GitHub and GitHub Enterprise repositories. The check is only raised for repositories that actually publish tags — a repository with no tags has nothing to protect. |
Coverage is evaluated per tag against the ruleset’s ref-name scope: a ruleset restricting update and deletion but scoped to refs/tags/v* protects v1.2.3 but leaves release-2024 mutable, so that tag is reported. A ruleset that only enforces a naming pattern or signatures — without restricting update and deletion — does not make tags immutable and will still be reported.
Impact context
The reported severity and message are modulated by how the repository’s tags are consumed:
-
Custom GitHub Action repository (an
action.yml/action.yamlat the root) — catastrophic, reported atcritical: consumers runuses: owner/repo@<tag>, so a moved tag executes attacker-controlled code in every consumer’s pipeline (the xygeni-action class of incident). -
Tag-triggered CI/CD (
on: release, oron: pushwith atags:filter) — a re-pointed tag runs the pipeline against tainted code. -
Published releases — release artifacts are resolved by tag, so consumers downloading by tag receive tampered content.
Security
Tag immutability is the control that stops tag-poisoning supply-chain attacks. If an attacker who has gained write access (or a compromised token/bot) can move a widely-consumed release tag to attacker-controlled code, every downstream pipeline that pins to that tag will silently execute the malicious version on its next run.
Mitigation / Fix
Create a GitHub ruleset that targets tags and, at minimum:
-
Restrict updates — prevents an existing tag from being moved to a different commit.
-
Restrict deletions — prevents a tag from being deleted (and recreated elsewhere).
Set the ruleset enforcement to Active, and scope its target tag pattern to your release tags (for example v*). See Managing rulesets for a repository.
Configuration
To change these options you can modify SCANNER_DIR/conf/misconfigurations/tag_protection.yml. The following are the default configuration properties:
# Configuration for the tag immutability check.
properties:
# If true, require an active GitHub ruleset (target: tag) that restricts both tag update and deletion.
requireTagImmutability: true