Whose code am I running in GitHub Actions?

ingve | 222 points

Unfortunately this makes a mistake by using a short commit ID: "(e.g. a5b3abf)"

That's not a full commit ID, so it can still result in a mutable reference if either someone can find a clash[1] or if they can push a tag with that name and it takes priority in the context it is used (this is somewhat complex, e.g. GitHub prohibits pushes of branches and tags which are exactly 40 hex characters long, but other services may not).

[1]: https://people.kernel.org/kees/colliding-with-the-sha-prefix...

dgl | a month ago

SHA pinning won't necessarily help if the dependency you are pinning doesn't pin its own dependencies! You still get stuff pulled via vulnerable tags etc. How long till we get this https://github.com/github/roadmap/issues/592 ...

mmmaantu | a month ago

There seems to be a slight misunderstanding in the article. It says that the "v2" tag "looks like an immutable reference" and points out that it's actually mutable, as if this was surprising and unintended. It also says that the reason people use tags despite this (making a tradeoff against security) is that "tags are easier to read and compare".

But the GitHub documentation [0] makes it clear that tags for major versions are intended to be mutable and be updated to point to new minor versions as they are released, not because it's "easier to read" but because you "can expect an action's patch version to include necessary critical fixes and security patches, while still remaining compatible with their existing workflows" (as long as the author follows their recommended semantic versioning scheme).

So choosing a major-version tag is GitHub's recommended practice precisely because it is mutable and does change.

[0] https://docs.github.com/en/actions/sharing-automations/creat...

ptx | a month ago

I just started using GitHub Actions for a personal project, and as you do, I trawled HN for opinions on how to use it.

At first I built a workflow out of steps published on GitHub. Use ilammy/mms-dev-cmd, lukka/get-cmake, lukka/run-vcpkg, all to build a project with CMake for Windows targets. Of course I referred to actions by SHA like you should

   uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756
But one comment stuck with me. Something like, “You should just run your own code on GitHub Actions, rather than piecing it together from publicly available actions.” That made a lot of sense. I ended up writing a driver program for my personal project’s CI builds. One job builds the driver program, and then the next job runs the driver program to do the entire build.

I wouldn’t do this if I were getting paid for it… it’s more time-consuming. But it means that I am only minimally tied to GitHub actions. I can run the build driver from my own computer easily enough.

dietrichepp | a month ago

Github Actions is definitely a vector for abuse.

I was looking at Seleniumbase recently, and they tell you that you can use Github Actions for web scraping to bypass a lot of blocks (apparently Github Actions use a residential IP-space)

https://seleniumbase.com/new-video-unlimited-free-web-scrapi...

bdcravens | a month ago

I've never liked the idea of community actions in the critical build path, so I use official actions/* when I can, and otherwise use actions/github-script to invoke the GitHub API via inline JavaScript when I can't.

dqh | a month ago

> At a glance, this looks like an immutable reference to an already-released “version 2” of this action, but actually this is a mutable Git tag. If somebody changes the v2 tag in the tj-actions/changed-files repo to point to a different commit, this action will run different code the next time it runs.

The worst part of this is that this is BY DESIGN.

I maintain a small handful of actions. You are expected to, as an action maintainer DELETE and RETAG your major versions when you release a new minor or patch version. That is to say for instance your v2 tag should point to the same commit as your latest 2.x.x tag.

Not everyone does this mind you, but this is the default and the expected way of operating.

I was frankly kind of taken aback when I learned this. I know for a fact documentation of this used to exist, but I am failing to find it currently.

You can see GitHub themselves however doing exactly this here, with the v4 and v4.2.2 tags matching here (as of today, v4 will move in future)

https://github.com/actions/checkout/tags

donatj | a month ago

This article appears to be in response to the linked Tj-actions/changed-files GitHub Action Compromised – used by over 23K repos discussed at https://news.ycombinator.com/item?id=43367987 10 days ago; not a duplicate as it discusses a detection tool but perhaps it rhymes.

password4321 | a month ago

This is a minor worry when the entire software ecosystem is based on “download any old shit off the Internet at run it”.

ohgr | a month ago

> Tags vs commit IDs is a tradeoff between convenience and security.

Well, it's also a trade-off between security and security. If you specify an immutable commit ID, then if the dependency releases a security update you won't get it until you notice and update the commit ID. If you specify a tag, you'll get it on next build.

I guess we need Dependabot updating commitID's in workflows too? But then they'd update you to the vulnerable new @2, how would they know otherwise if it hadn't been reported yet?

jrochkind1 | 25 days ago

Wait, people actually just blindly paste together calls into GitHub actions written by someone else who can change it at any time?

You know what, no this makes perfect sense. This is exactly, perfectly in line with the modern software ethos.

Jesus. I'm so glad that 100% of my GitLab pipelines is code I wrote. It's owned by the company and it lives in our source control and runs on our hardware. I think you'd be nuts to do anything else, honestly.

For entirely related reasons, I'm thrilled that my career is moving in a direction away from devops and software in general. I can't stomach it anymore.

mystified5016 | a month ago

GitHub’s dependency graph is supposed to give us this kind of visibility without any custom scripting, but from my experience it’s pretty spotty and often misses dependencies entirely.

Also, the script from the article doesn’t cover transitive GitHub Actions dependencies. So if a third-party action you’re using relies on a vulnerable action internally, it won’t catch that.

ph3t | a month ago

https://github.com/orgs/github/projects/4247?pane=issue&item... - GitHub is working on immutable actions. Let's see then how they really work...

ippem | a month ago

There is a breakdown in UX if your references need to look like this

SHA `11bd71901bbe5b1630ceea73d27597364c9af683`

That means absolutely nothing to a human being Whereas

> hashicorp/setup-terraform@v3

Is easy to understand.

How about

> hashicorp/setup-terraform!v3.0.1

This version, and only this version, fails if the version cannot be found.

Or

> hashicorp/setup-terraform@v3-2025-03-26-15-01

Give me the version of the library as it was at this specific time or fail if it can't be found

Presumably it would be wise to check the SHA as well to ensure no changes have taken place maliciously

One could go old school and import the code from the various needed libraries, into the main project. Now you have complete control over what runs and it can be audited and will be in a safe state until explicit action is taken to update the code.

ThinkBeat | 25 days ago

Actions are not immutable, period: https://github.com/github/roadmap/issues/592. This issue has been open for years and continues to be pushed back, so I would not recommend anyone use any github action as a dependency if they want to protect against supply chain attacks (basically, don't use GHA at all, it's a horrible product if you care about cost/performance/security).

You also cannot trust a git commit ID as an immutable reference. Even if you have a checksum available, you have to validate it.

duped | 25 days ago

This has been in GH's docs on security hardening for a while[0], and I can't recall which tool it was, but I have seen reports that warn when not using SHAs. Pretty sure there was a linter that would even show the warning in my neovim setup that uses some kind of gh action LSP, but it has been a minute.

[0]: https://docs.github.com/en/actions/security-for-github-actio...

Jenk | a month ago

When I saw the tj-actions attack, I decided it was time to finally implement action wrapping with our `witness-run-action`. This will generate signed attestations on exactly what the actions are doing.

We have some more testing to do before we cut an official release, but it is working correctly for the limited cases we have tested it with. I'd love this group's feedback.

https://github.com/testifysec/witness-run-action/tree/v1.0.1...

colek42 | a month ago

> Tags vs commit IDs is a tradeoff between convenience and security. Specifying an exact commit ID means the code won’t change unexpectedly, but tags are easier to read and compare.

Imagine if we could specify both the tag and its commit, and the runner would check, at run-time, whether the specified tag is still pointing to the specified commit. This would essentially "lock" the dependency. Although storing such "locks" inline would probably be a bit too ugly, maybe we could instead collect them all and store them in a separate "file of locks", so to speak. Does anyone know if something like this has been tried before or am I just making up stupid stuff?

Joker_vD | a month ago

I always felt that Gitlab CI was a lot more understandable. But in Gitlab CI, just as in Github Actions, you're usually running some container. And aside from the container you're also running some globally defined actions.

That's the most obfuscated part for me, the globally defined actions that can belong to any organisation in Github.

In Gitlab it was at most a globally defined git repo with templates, but you could somehow understand it better.

INTPenis | 25 days ago

A better solution would be to use something like Forgejo Actions, Woodpecker CI, or Drone for a self-hosted, private setup and avoid the dependency on GitHub Actions altogether. Some of these self-hosted solutions have compatibility with GitHub Actions syntax, so the workflow would be more or less the same while having less risk for these type of attacks.

smjburton | 25 days ago
[deleted]
| a month ago

You can use [ratchet](https://github.com/sethvargo/ratchet) to manage your GH action pointers.

ian1321 | 25 days ago

Right, but lets get real here: GitHub Actions is fundamentally insecure. You are blindly trusting upstream libraries and GitHub itself to respect and protect your secrets.

fergie | a month ago

Oh man, this doesn't sound too different from all those people (definitely not me) with hundreds of npm libraries in their dependency tree..

apt-apt-apt-apt | a month ago

@actions/upload-artifact brings in 2 million bytes of javascript code to upload a file to the job artifact list.

infogulch | 25 days ago

we have a tool that does this and more...

it is as easy as running the action and writing a SQL query.

https://yeet.cx/blog/audit-actions-runner/

can also play with it using:

https://yeet.cx/play

r3tr0 | a month ago

GitHub's own official tutorials use tags instead of full commit shas. What a mess.

dpkirchner | a month ago

[dead]

samjohn2025 | a month ago