feat: initial cache-poisoning audit#294
Conversation
259018b to
a67519e
Compare
|
Thanks @ubiratansoares! I'll try and do an initial pass on this today or tomorrow. |
|
|
||
| let trigger = &step.workflow().on; | ||
|
|
||
| if !self.trigger_used_when_publishing_artifacts(trigger) { |
There was a problem hiding this comment.
This looks good for now, thanks!
Thinking out loud: another future proxy we could use for "is this a publishing workflow" is whether or not the workflow contains any well-known publishing actions, e.g. gh-action-pypi-publish.
Not something to do with this iteration, but worth thinking about 🙂
a67519e to
accbdbd
Compare
|
@woodruffw Addressed your suggestions, let me know whether I missed something! Docs to follow 🙂 |
|
Thanks! I think that's everything -- just undraft and give me a ping when you're ready for a final review! |
|
@woodruffw Added some docs here, let me know what you think :) Some follow-ups from this PR, so we can keep its size manageable for the review:
|
|
Added this additional commit to highlight another (potential) follow-up : should we evaluate |
| pub(crate) fn as_template(&self) -> String { | ||
| format!("{}/{}", self.owner, self.repo) | ||
| } |
There was a problem hiding this comment.
Created this new method as a helper, since I need to get a template from what we have in well-know list, essentially due the asymmetrical nature of RepositoryUses::matches
There was a problem hiding this comment.
I don't love that we have to re-build the slug here, but that's my fault for building a bad abstraction here 😅 -- I'll try and clean this up as part of the final review.
|
Thanks! I'll give this a final pass tomorrow, but this is looking great to me! Let's track the follow-ups in #294 (comment) with a new issue 🙂 |
Signed-off-by: William Woodruff <william@yossarian.net>
Allow `RepositoryUses::matches` to take `impl TryInto<RepositoryUses>` instead, which has an auto-derived infallible impl for `RepositoryUses` itself. Signed-off-by: William Woodruff <william@yossarian.net>
GHA doesn't know the difference between `true` and `'true'`, so neither should we. Signed-off-by: William Woodruff <william@yossarian.net>
|
|
Signed-off-by: William Woodruff <william@yossarian.net>
Signed-off-by: William Woodruff <william@yossarian.net>
woodruffw
left a comment
There was a problem hiding this comment.
LGTM, great work @ubiratansoares!
A first iteration on #261
There is a lot to unpack in this PR already, so I added several inline comments, and I'll go for docs as soon as we are good with the overal design 🙂
First consideration : for now, I'm matching as triggers for this audit only
releaseandpush(with tags filters).I'm aware that more scenarios exist : I myself use another pattern (on top of
workflow_dispatch), happy to get input and iterate, or eventually tackle them as a follow-up. I miss a check for the default branch of the repo, but since it requires querying the Github API, I've skipped it for now.Second consideration: because of the multitude of caching-aware Actions that exist (and how they behave), and because we should aim to consume a static API at some point in the future, I've modelled a
CacheAwareActionstruct, which is the very core of this PR.In general, I tried to capture with this data holder:
actions/setup-go)actions/cache)actions/setup-node)There is a static list of
CacheAwareAction, covering all Actions provided by Github and a few others. Happy to add as many as we want to have 🔥Third consideration: I defined a strategy for this audit on top of a chat I had with Adnan, focusing on the unzip part of cache-poisoning attacks. This means I'm not considering
actions/cache/savein the Actions we inspect for.Most of the Actions I've listed bring both saving/restoring out-of-the-box, but some of them define a
lookup-onlyinput (as peractions/cacheandactions/cache/restoredo), that only queries the Github API for cache entries but do not download any caches. Maybe this is incomplete/insufficient, and I'd love to get inputs here!Last but not least : I added several examples of vulnerable Workflows and snapshot test all of them.
Most likely I missed other things, but hopefully this PR sesa a place to get started 🙂