Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial cache-poisoning audit #294

Merged
merged 13 commits into from
Dec 19, 2024

Conversation

ubiratansoares
Copy link
Contributor

@ubiratansoares ubiratansoares commented Dec 13, 2024

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 release and push (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 CacheAwareAction struct, which is the very core of this PR.

In general, I tried to capture with this data holder:

  • that some actions will run caching behavior by default, both for saving and restoring (eg actions/setup-go)
  • that some actions have an input that allows either with opt-in or opt-out from restoring cache (eg actions/cache)
  • that some actions define opt-in not by specifying a boolean input, but actually a set of values (eg actions/setup-node)
  • eventually the user opts-in for caching on top of an expression: there is not much to do, but I keep track of that

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/save in 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-only input (as per actions/cache and actions/cache/restore do), 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 🙂

@woodruffw
Copy link
Owner

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) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 🙂

@woodruffw woodruffw added enhancement New feature or request new-audit New audits labels Dec 13, 2024
@ubiratansoares
Copy link
Contributor Author

@woodruffw Addressed your suggestions, let me know whether I missed something! Docs to follow 🙂

@woodruffw
Copy link
Owner

Thanks! I think that's everything -- just undraft and give me a ping when you're ready for a final review!

@ubiratansoares
Copy link
Contributor Author

ubiratansoares commented Dec 17, 2024

@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:

  • Evaluate the presence of well-know publish-like Actions (e.g. gh-action-pypi-publish) in addition to the trigger-based evaluation
  • Improve evaluation for push trigger with well-know branch paths (eg, release-* branches) ?
  • Add more Actions in the list of well-know cache-aware Actions 😄

@ubiratansoares ubiratansoares marked this pull request as ready for review December 17, 2024 09:33
docs/audits.md Outdated Show resolved Hide resolved
@ubiratansoares
Copy link
Contributor Author

ubiratansoares commented Dec 17, 2024

Added this additional commit to highlight another (potential) follow-up : should we evaluate step.if to avoid some false positives, since the user can avoid cache restoration by disabling the a cache-aware step?

src/models.rs Outdated
Comment on lines 593 to 595
pub(crate) fn as_template(&self) -> String {
format!("{}/{}", self.owner, self.repo)
}
Copy link
Contributor Author

@ubiratansoares ubiratansoares Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@woodruffw
Copy link
Owner

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>
@woodruffw
Copy link
Owner

woodruffw commented Dec 19, 2024

ee7d227 (#294) tweaks the audit slightly so that it catches our own problematic pypi.yml workflow. I need to think about how best to fix that, plus how best to ensure this audit sees our fix.

Signed-off-by: William Woodruff <william@yossarian.net>
Signed-off-by: William Woodruff <william@yossarian.net>
@woodruffw woodruffw changed the title feat: initial iteration on cache-poisoning audit feat: initial cache-poisoning audit Dec 19, 2024
@woodruffw woodruffw enabled auto-merge (squash) December 19, 2024 03:40
Copy link
Owner

@woodruffw woodruffw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, great work @ubiratansoares!

@woodruffw woodruffw merged commit 10e9fe3 into woodruffw:main Dec 19, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request new-audit New audits
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants