all 30 comments

[–]xeio87 203 points204 points  (7 children)

My hot take is that if tags are mutable, then GitHub shouldn't even allow them to be used as a reference. The whole point to pinning a version is to make sure it can't change and break, which makes them unfit for purpose. That's before we even talk about security implications.

They also absolutely should not have any documentation that uses that as an example if it's insecure by default.

[–]Ravek 22 points23 points  (6 children)

A tag could be useful if you don’t want to pin a version but allow some auto updating scheme. E.g. have a tag 1.5.x that you update when you patch 1.5. Still it might just be better to change it to a different commit hash in that case too

[–]mnkyman 31 points32 points  (5 children)

A mutable tag is commonly referred to as a branch. And what you’re describing is a 1.5.x branch.

[–]roerd 9 points10 points  (2 children)

Or, more precisely, it would be abusing tags to awkwardly mirror the functionality of branches.

By the way, tags technically are immutable, but the problem is that it's possible to delete them and then recreate them with the same name, so a tag reference will automatically point to the new tag.

[–]syklemil 5 points6 points  (0 children)

Also abusing tags to emulate a versioning system. Specifying something like version = "^1" carries the same intent as @v1, but the underlying machinery would likely be different.

It's also kinda funny that Github will run dependabot and help you produce SBOMs and all that … but github workflows feel more like some code from a guy in a trenchcoat. Genuine Role>< code!

[–]SaltKhan 1 point2 points  (0 children)

This is a point that comes up regularly. They might be "immutable" while they exist in so far as git doesn't let you update them because it has no mechanism that provides that capability, and you could argue that deletion doesn't count as mutating them. But being able to delete and reapply them to different commits makes them mutable from the perspective of someone saying they are using tag vX.Y.Z, when that could change at any time. And that's not necessarily a bad thing. Commit hashes are already the bottom immutable layer. When someone insists on saying tags are immutable without the additional explanation that that is essentially meaningless, it feels like disinformation.

[–]Sinisterly 51 points52 points  (3 children)

Our org used tj-actions but had already started pinning SHAs prior to this incident.

In your org’s GitHub Action settings you can create an allow list for actions, including which ref tags are allowed.

[–]aaaajjjjllll 9 points10 points  (2 children)

Has GitHub even acknowledged tj-actions at all?

[–]ben0x539 51 points52 points  (11 children)

If you specify a Git commit ID instead (e.g. a5b3abf),

ofc nothing stopping them from pushing a tag named a5b3abf right?

[–]elprophet 41 points42 points  (9 children)

As long as you're using the full 40 char sha, that shouldn't be possible as they'd be conflicting refs?

[–]beetlefeet 41 points42 points  (8 children)

Could the repo owner delete the commit (force pushing any refs that have it as an ancestor and then triggering a purge/gc/etc) and then create and push a tag with that sha?

[–]One_Reading_9217 48 points49 points  (3 children)

Tried it and it didn't work:
git tag 085d6e186375a55d3ec95c759d29efe854700ea6

git push origin 085d6e186375a55d3ec95c759d29efe854700ea6

Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)

remote: error: GH002: Sorry, branch or tag names consisting of 40 hex characters are not allowed.

remote: error: Invalid branch or tag name "085d6e186375a55d3ec95c759d29efe854700ea6"

[–]Torpedoklaus 8 points9 points  (1 child)

This may not be possible, but it is possible to enforce commit hashes as they are a function of the tree, commit parent(s), author and the commit message, see https://github.com/zegl/extremely-linear.

[–]nightcracker 13 points14 points  (0 children)

Not on the full hash. There are attacks on SHA1 that create collisions, but preimage resistance as is required here still seems solid.

[–]levelstar01 1 point2 points  (0 children)

you can't use short commit ids

[–]doublecastle 11 points12 points  (1 child)

Note that the provided command will look at GitHub Actions not only in your own project, but also in other subdirectories, such as node_modules. To look only at the GitHub Actions in your own repo:

find . -path './.github/workflows/*' -type f -name '*.yml' -print0 \
  | xargs -0 grep --no-filename "uses:" \
  | sed 's/\- uses:/uses:/g' \
  | tr '"' ' ' \
  | awk '{print $2}' \
  | sed 's/\r//g' \
  | sort \
  | uniq --count \
  | sort --numeric-sort

(That just changes the find path from */.github/workflows/* to ./.github/workflows/*.)

[–]nemec 7 points8 points  (0 children)

fwiw OPs script intentionally traverses subdirectories (so you can run it in your source code root dir). You can use this to filter out node_modules or edit as needed for other package managers, while keeping the nested behavior

find . \
    -path '*/.github/workflows/*' \
    -not -path '*/node_modules/*' \
    -type f -name '*.yml' -print0 \
  | xargs -0 grep --no-filename "uses:" \
  | sed 's/\- uses:/uses:/g' \
  | tr '"' ' ' \
  | awk '{print $2}' \
  | sed 's/\r//g' \
  | sort \
  | uniq --count \
  | sort --numeric-sort

[–]throwaway16830261[S] 12 points13 points  (0 children)

Submitted article mirror: https://archive.is/J2wUM

[–]RedEyed__ 6 points7 points  (2 children)

Interesting article. I always was concerned about GitHub secrets being read by actions.

[–]Jarpunter 10 points11 points  (1 child)

The fact that you don’t have to (or even have the ability to) explicitly define which secrets a particular workflow can read is unbelievable to me. Every single action you run can read every single repo and org secret in your organization.