GitHub Actions is the weakest link(nesbitt.io) |
GitHub Actions is the weakest link(nesbitt.io) |
I feel rather vindicated now. There's still a small possibility of getting supply-chain attacked via a SHA collision, or a relatively much larger (though still small in absolute terms) possibility of getting supply-chain attacked via NPM dependencies of the action you're relying on.
But if you're not using a commit hash in your `uses:` lines, go switch to it now. And if you're just using major-version-only tags like `v5` then do it RIGHT now, before that action gets a compromised version uploaded with a `v5.2.3` tag.
We recently found (in Renovate) some edge cases with how tags work in GitHub Actions which was fun (https://news.ycombinator.com/item?id=47892740) and there's a few things in there Dependabot doesn't seem to support too
Zizmor recently shipped a rule to warn of such actions, but it only does it for two known actions so far.
Indeed. To illustrate why:
1. It is not possible to "retroactively" find a SHA-1 collision for an already known hash. If somebody has produced a SHA-1 hash non-maliciously at any point in the past, it is safe from collisions. This is due to second-preimage resistance, which hasn't been broken for SHA-1 and doesn't seem likely to be broken any time soon.
2. The only way to obtain a SHA-1 collision is to do so knowingly when producing the original hash. You generate a pair of inputs at the same time that both hash to the same value. Certainly, this is an imaginable scenario; e.g. a trusted committer could push one half of the pair wittingly or a reviewer could be fooled into accepting one half of the pair unwittingly, both scenarios creating a timebomb where the malicious actor swaps the commit to the second half of the pair (which presumably carries a malicious payload) later. However, there are two blockers to this approach: Git (not just GitHub) will not accept a commit with a duplicate hash, always sticking with the original one, and GitHub specifically has implemented signature detection for the known SHA-1 collision-generating methods and will reject both halves of such a pair.
In short, there's just no practical way to exploit this weakness of SHA-1 with Git.
I wrote a couple of blog posts on it, and a makeshift way of tackling that https://developerwithacat.com/blog/202604/github-actions-sup...
zizmor (and other tools) correctly recovers vulnerability information for SHA-pinned actions[1].
[1]: https://docs.zizmor.sh/audits/#known-vulnerable-actions
Renovate handles this well. Ratchet and pinact can also be used
I don’t think this problem is fixable without a higher level way to specify the full nested tree. Something like TOFU for the first time your action ran (pinning all children as of that run) might be an improvement, but that is still can be gamed by a timed attack that modifies the action at a later date (literally, if time greater than X do …).
Or, if you just want to talk about the future of CI with like-minded systems engineers, without committing to using a particular product, consider joining our Discord: https://discord.com/invite/dagger-io
But I totally agree that the Jenkins langs are terrible, the errors even worse, somehow they managed to make jvm backtraces even more unreadable.
CI must only consist of shell commands. No abstractions, no surprises. (Except maybe with PowerShell, where the principle of most surprise rules.)
- https://github.com/sethvargo/ratchet for pinning external Actions/Workflows to specific commit hashes
- https://www.warpbuild.com/ for much faster runners (also: runs-on/namespace/buildjet/blacksmith/depot/... take your pick)
- soon moving to Buildkite for orchestration of our CI jobs
I still just need a reasonable alternative for the "store our git repo, allow us to make and merge prs" part of things. Hopefully someone takes all the pieces that the Pierre team is publishing and makes this available soon. The Github UI and the `gh` cli are actually really nice and the existing alternative code storage tools are not great IMO.
We optimize for overall performance in real world jobs and have a broad selection of regions/OSes/arch available. There aren't any fixed subscription fees either.
It's always been poo, the YAML is bad, the reliability is bad and the cost is bad.
So there is really no redeeming features because even if you tout forge integration it's UI is, you guessed it, also bad.
Putting aside the anti-pattern of using vendor YAML for literally anything (please don't do that) you are distinctly better off with literally any other CI/orchestration service. Buildkite is good, dynamic pipeline = good, there are other good options. If you are a serious person you will find good things to use.
Getting back to vendor YAML, please just use a real build system instead. Define all the actual logic there with entry points/targets the YAML hits. Also generally make sure that you don't need the actual CI system to be up to do releases, deployments etc. A sufficiently elevated local user should be able to run the appropriate target with the appropriate credentials to get the job done in absence of said CI system.
I was heartbroken when Microsoft bought it. There should be a way for citizens to rebel against such things. It feels like it's been on a downward trajectory ever since.
I got frustrated with the lack of security to started working myself on an open-source runtime sandbox for GHA: https://github.com/electricapp/hasp
The first check was inspired by the trivy attack. hasp enforces SHA pinning AND checks that a comment (# v4.1.2) actaully resolves to its preceding SHA. That grew into a larger suite of checks.
Instead of just statically parsing YAML it hooks into the runner env itself. Some of its runtime checks mirror what zizmor already does including resolving upstream SHAs to canonical branches (no impostor commits) and traversing the transitive dependency tree. I have a PR up with a comparison document here (hasp vs. zizmor): https://github.com/electricapp/hasp/pull/13/changes#diff-aab...
Furthermore, it sandboxes itself to prevent sensitive exfiltration by acting as a token broker which injects the secret at runtime -- the GH token can only ever be used to call the GH API. It uses landlock, seccomp, and eBPF via Rust, so no docker. The token broker sandbox can also be used to wrap a generic executable giving hasp generic applicability beyond GHA context (i.e. agentic or other contexts, where token runtime injection seems quite in vogue)
I'm using this as a stopgap until GH rolls out some of the features on its roadmap. I'm moving torward treating the runner as a zero-trust or actively malicious environment, so this was my small contribution on that front.
The reason I use them, however, is because its more trouble than its worth to maintain build servers for the 3 platforms I care about (Windows, macOS, Linux) myself. Especially for projects that get built sporadically. I think one reason for this pain is that while you can easily run VMs for Windows and Linux on the same host, macOS is kinda its own special unicorn and might need a dedicated box. (But even that aside, maintaining machines you don't use every day can get annoying.)
[1]: https://blog.howardjohn.info/posts/blacksmith-gha/
[2]: https://binhong.me/blog/github-action-runner-alternatives/
This has downsides of course, moving further into the "everything rot so fast these days" trope, but we will in a adversarial world where the threat is constantly evolving.
Tomorrow (today) the servers and repo won't be scanned by scripts anymore but by increasingly capable models with knowledge about more security issues than many searchers.
Github actions is running like treacle now. Even when our company pays lots of money for cloud and private Github runners.
I know its the go-to punchbag but I think enabling Copilot reviews globally for a large proportion of Github was a bit hasty.
The security problems aside, if it continues this way, people won't be able to ship and deploy code from Github actions.
We might dare I say it, have to go back to self hosted Jenkins or Travis CI.
Lately i don't use any managed services and life couldn't be any simpler.
The security risk for running unvalidated code on any random PR with access to account secrets has no legitimate use case which outweighs its unbounded risk.
Am I thinking of someone else or did you reverse on that?
We are actively overhauling our design (in a backwards compatible way) to reach a better balance. The result is that, for most users, writing custom code will not be required to use Dagger. But it will be available for power users who want to extend and customize the platform. Writing code for Dagger will be less like using a frameworok, and more like writing a plugin for a devops tool.
If you're interested, you can track our progress in our combined changelog / roadmap page: https://dagger.io/changelog/#modules-v2 . The overhaul project is called "modules v2".
Perhaps once it ships, you can give Dagger another try :)
In practice this means you can combine Dagger with, say, Github Actions or another "legacy" CI platform. And use it as runner & event infrastructure for your portable Dagger pipelines.
We also offer a complete Dagger-native CI platform, which combines hosted Dagger engines, git triggers, and all the infrastructure necessary to run your CI end-to-end. That is in early access as part of Dagger Cloud, our commercial offering.
Gradle did it successfully and it's great now.
But I never tried it personally
On zizmor, there's no mention of coverage on commit SHA the section you've linked, nor in the entire page when I do Ctrl+F. Is there anything I'm missing?
You can see it in the source here[1].
[1]: https://github.com/zizmorcore/zizmor/blob/db5ed6b3bb445848a8...
To make matters worse, you'd lose getting alerts on vulnerabilities. Dependabot won't send them, and neither will Renovate last time I checked.
- raises PRs for security fixes immediately, regardless of cooldown configs
- flags the PRs as security fixes
- does the above when actions are pinned by commit SHA
? If so, mind sharing some documentation and examples please? I don't mind being proven wrong, but I genuinely couldn't find anything that demonstrates this happens. Dependabot docs actually point to the contrary (see my blog posts).