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
Feature: Check for usage of on: workflow_run trigger #3861
Comments
How would we define / detect privilege? |
Could that be left as an exercise for the repo owner deploying Scorecard? Or make an assumption one way or the other with an allowlist/denylist? |
One indicator of privilege is any action in workflow-b uses a secret (e.g. |
Question: if Basically, does it consider that I'm in doubt because I never fully understood which commit is used when CI runs on a PR – it's not the PR's HEAD, but the merge commit between the PR and main, or something like that. If setting |
Scorecard already checks for workflow_run trigger + RCE https://github.com/ossf/scorecard/blob/main/checks/raw/dangerous_workflow.go#L62. |
The question here isn't so much RCE, but getting a workflow_run to trigger at an unexpected time. Fleshing out the example given above, let's say we have a repository that follows Continuous Delivery, where all commits to
# build-and-test.yml
on:
push:
jobs:
test:
steps:
- # ... build ...
# upload artifact for release or manual debugging if necessary
- uses: actions/upload-artifact
with:
- artifact-name: release-artifact
- run: ./test.sh and # release.yml
on:
workflow-run: [build-and-test]
types: [completed]
branches: [main]
jobs:
release:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
# ...
steps:
# ...
- run: ./download_artifact
env:
WORKFLOW_RUN_ID: ${{github.event.workflow_run.id }}
- run: ./release.sh If a PR is sent that changes So As for my previous comment, I did some digging and this does indeed seem to work, even though |
Yes, precisely. The problem is what happens when the PR described in Raghav's original post is sent: # build-and-test.yml
on:
push:
branches: [ main ]
+ pull_request:
+ branches: [ main ] When such a PR is sent, |
Thanks, I get it now. Great finding. Essentially it does not keep track of the original context at the @raghavkaul did you see this pattern used in several repos? @josepalafox @steiza what do you think? |
I think that today if you're a public repository you need to choose between:
Today, if you do both, you are likely to be bitten by a scenario like what is listed above. I realize this is not ideal! This is something we're aware of and thinking about, but I don't have a better solution to offer you today. |
Hey @steiza, thanks for replying. Just to clarify, though: is the fact that That is, is the fact that the workflow below runs when the triggering workflows runs on a new PR "working as intended"? on:
workflow_run:
workflows: [Run Tests on PRs and Main]
branches: [main] In my opinion, that's quite unintuitive and should likely be made clear in the docs. |
Oh, maybe this is a syntax/indentation issue? Again, I want to re-iterate that (as illustrated by this thread) you have to be very careful when relying on Actions syntax to secure access to highly privileged Actions workflows. If you have a public repository with privileged workflows, I would strongly recommend enabling "Require approval for all outside collaborators". That said, I was not able to reproduce what you described here. Here were my two workflows:
In a non-main branch I added this diff:
And then I pushed (which was enough to trigger The indentation is really important here! At the top of this issue you listed:
... but then on #3861 (comment) you listed:
The first example will give you the protection you're looking for, but the second example will not apply the |
Hey @steiza, here's an MRE of the issue: https://github.com/pnacht/test-workflow-run-pr This is a toy project with two workflows: name: workflow-run
on:
workflow_run:
workflows: [other]
types: [completed]
branches: [main]
# ... name: other
on: push
# ... Looking at the Actions tab, we can see that I sent a "local PR" that modified
Looking at the Actions tab, we can see that However, when Spencer creates a fork and sends an identical external PR directly from his So it seems like |
Oh, thank you @pnacht! What I missed earlier was that the pull request was coming from the fork network, not a branch in the originating repository. I'll escalate internally. |
@steiza Any update on whether the branch field is supposed to match any branch on any repo with the specified name, or just the named branch from the source repository? The latter means this behavior can only be exploited if a contributor already has write/branch creation access. |
I think it's meant to match only the branch on the source repo. But there's still logic we can add in scorecard to also test the part where the indentation makes it vulnerable to external users sending PR: on:
workflow-run: [build-and-test]
types: [completed]
branches: [main] |
I don't know how feasible it'd be, but that seems like something that GitHub should perform while validating a workflow's schema, not something Scorecard should have to check... |
It's not unreasonable for Scorecard to check for this anyway though. Consider the case where a |
yes that was my thinking. It's fairly easy to use the filter at the wrong indentation level by mistake. Curious how many workflows are configured this way on GitHub :) |
Ah, agreed, checking whether I just don't think Scorecard should also evaluate for the specific "got the indentation wrong" error, which seems like something GH should simply reject as an invalid workflow (since the |
Sorry. I don't mean the workflow is invalid. I mean that indentation makes the workflow vulnerable: on:
workflow_run:
workflows: [Run Tests on PRs and Main]
branches: [main] // Or no branch at all instead of: on:
workflow_run:
workflows: [Run Tests on PRs and Main]
branches: [main] |
Yes, I understand. I simply believe that the first case should cause the workflow to crash, with GH rejecting the workflow as invalid; the |
The branch field should be for the named branch in the source repository - not a branch on any repository in the fork network. |
as far as our parser is concerned these are the same thing though. But yes for anyone not using Scorecard that's another story |
Not necessarily. Scorecard's parser can simply care about whether That being said, there's also the issue of whether we believe GitHub will actually make the workflow fail if it doesn't follow |
I just meant that not having a branches filter and having the wrong indentation are the same thing if all we're doing is checking if |
Is your feature request related to a problem? Please describe.
GitHub Actions supports
on: workflow_run
as a workflow trigger. This trigger (and potentially alsoon: workflow_call
) allows chaining of workflows in a way that can lead to unintentional execution of a GitHub workflow through a contributor's open pull request.Consider two workflows:
workflow-a.yml:
workflow-b.yml:
Now consider a pull request by a first-time contributor (or, if the maintainers require workflow approval for first-time contributor, consider a contributor that has submitted a small patch already):
workflow-a.yml (modified in PR):
Mitigating factors
If
workflow-b.yml
is not a "privileged action" (e.g. pushing code, modifying artifacts, modifying tags), then the risk from this workflow is low. This is because a workflow triggered withon: workflow_run
uses the workflow definition on the default branch. We should discuss how to prevent false-positives here.Describe the solution you'd like
The Dangerous-Workflows check should flag for uses of the
on: workflow_run
trigger that could allow a pull request to execute privileged actions.The text was updated successfully, but these errors were encountered: