Skip to content

Actions: Fix dominates() false positive in reusable workflows#21986

Open
JarLob wants to merge 3 commits into
github:mainfrom
JarLob:userpermissions
Open

Actions: Fix dominates() false positive in reusable workflows#21986
JarLob wants to merge 3 commits into
github:mainfrom
JarLob:userpermissions

Conversation

@JarLob

@JarLob JarLob commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@JarLob JarLob requested a review from a team as a code owner June 15, 2026 05:49
Copilot AI review requested due to automatic review settings June 15, 2026 05:49
@github-actions github-actions Bot added documentation Actions Analysis of GitHub Actions labels Jun 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates the CWE-829 “Untrusted Checkout (Critical)” query logic and fixtures to better recognize permission checks (including across reusable workflows) and to validate expected results.

Changes:

  • Extend ControlCheck dominance logic to account for checks that occur in the caller of a reusable workflow.
  • Add new GitHub Actions workflow fixtures covering permission-check patterns (and a “missing needs” negative case).
  • Update the expected test results to include the new fixtures/edges.
Show a summary per file
File Description
actions/ql/lib/codeql/actions/security/ControlChecks.qll Adds reusable-workflow caller coverage to control-check dominance logic.
actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected Updates expected edges/results for new workflow fixtures.
actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permissions_check.yml Adds fixture where collaborator permission check precedes checkout.
actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_permission_check_reusable.yml Adds fixture where permission check precedes a reusable workflow call.
actions/ql/test/query-tests/Security/CWE-829/.github/workflows/untrusted_checkout_no_needs.yml Adds negative fixture where the permission-check job exists but is not required by the checkout job.
actions/ql/test/query-tests/Security/CWE-829/.github/workflows/external/TestOrg/TestRepo/.github/workflows/build.yml Adds external reusable workflow fixture used by the tests.
actions/ql/lib/change-notes/2026-06-15-permission_check.md Adds changelog entry for the reusable-workflow support fix.

Copilot's findings

  • Files reviewed: 7/7 changed files
  • Comments generated: 1

Comment thread actions/ql/lib/codeql/actions/security/ControlChecks.qll Outdated
Comment thread actions/ql/lib/codeql/actions/security/ControlChecks.qll Fixed
@JarLob JarLob marked this pull request as draft June 15, 2026 06:34
@JarLob JarLob marked this pull request as ready for review June 15, 2026 06:52
@owen-mc owen-mc changed the title Fix dominates() false positive in reusable workflows Actions: Fix dominates() false positive in reusable workflows Jun 15, 2026

@redsun82 redsun82 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👋 thanks for this contribution, I think this is going in the right direction! Currently this is relaxing the check a little too widely though, if I got it right. It seems one caller having the correct permission check can hide other callers being unsafe. Could you double check that, and add it to the tests after fixing if I got that right?

// check if the control check dominates any caller job in the chain.
exists(ExternalJob directCaller, ExternalJob caller |
directCaller = node.getEnclosingWorkflow().(ReusableWorkflow).getACaller() and
caller = getAnOuterCaller*(directCaller) and

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this might be too broad when the same reusable workflow has multiple callers. Since dominates only takes the reusable-workflow node, this exists caller can make a check from one protected caller count as protection for the reusable workflow as a whole.

I've cooked up a scratch qltest with two callers to the same build.yml, one with needs: is-collaborator and one without. It turns out the unprotected caller does not produce an alert, because the protected caller is enough to satisfy this predicate. I guess we need to keep the protection tied to the specific caller/call path that produced the event, rather than any caller of the reusable workflow.

exit 1
build:
needs: is-collaborator
uses: TestOrg/TestRepo/.github/workflows/build.yml@main

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we also add a regression for the mixed-caller case? Something like this protected caller plus another job in the same triggering workflow that calls the same reusable workflow without needs: is-collaborator.

That seems to be the tricky case here, because otherwise the reusable workflow node can look protected just because one of its callers is protected.

---
category: fix
---
* GitHub Actions support for reusable workflows was improved. No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: maybe we could make this a little tighter? This sounds like a general reusable-workflow support improvement, while the change is more specifically about recognizing control checks around jobs that call reusable workflows.

Maybe something like:

Suggested change
* GitHub Actions support for reusable workflows was improved.
* GitHub Actions queries now better account for permission checks on jobs that call reusable workflows.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Actions Analysis of GitHub Actions documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants