diff --git a/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql b/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql index c8512e5a1c0c..d70d9a530a0e 100644 --- a/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql +++ b/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql @@ -31,15 +31,26 @@ private predicate isPinnedContainer(string version) { bindingset[nwo] private predicate isContainerImage(string nwo) { nwo.regexpMatch("^docker://.+") } -from UsesStep uses, string nwo, string version, Workflow workflow, string name +private predicate getStepContainerName(UsesStep uses, string name) { + exists(Workflow workflow | + uses.getEnclosingWorkflow() = workflow and + ( + workflow.getName() = name + or + not exists(workflow.getName()) and workflow.getLocation().getFile().getBaseName() = name + ) + ) + or + exists(CompositeAction action | + uses.getEnclosingCompositeAction() = action and + name = action.getLocation().getFile().getBaseName() + ) +} + +from UsesStep uses, string nwo, string version, string name where uses.getCallee() = nwo and - uses.getEnclosingWorkflow() = workflow and - ( - workflow.getName() = name - or - not exists(workflow.getName()) and workflow.getLocation().getFile().getBaseName() = name - ) and + getStepContainerName(uses, name) and uses.getVersion() = version and not isTrustedOwner(nwo) and not (if isContainerImage(nwo) then isPinnedContainer(version) else isPinnedCommit(version)) and diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/actions/unpinned-tag/action.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/actions/unpinned-tag/action.yml new file mode 100644 index 000000000000..782505cc698d --- /dev/null +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/actions/unpinned-tag/action.yml @@ -0,0 +1,6 @@ +name: Composite unpinned tag test +runs: + using: "composite" + steps: + - uses: foo/bar@v2 + - uses: foo/bar@25b062c917b0c75f8b47d8469aff6c94ffd89abb diff --git a/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected b/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected index ed35f1546171..7882cfaeb339 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected @@ -1,3 +1,4 @@ +| .github/actions/unpinned-tag/action.yml:5:13:5:22 | foo/bar@v2 | Unpinned 3rd party Action 'action.yml' step $@ uses 'foo/bar' with ref 'v2', not a pinned commit hash | .github/actions/unpinned-tag/action.yml:5:7:6:60 | Uses Step | Uses Step | | .github/workflows/actor_trusted_checkout.yml:19:13:19:36 | completely/fakeaction@v2 | Unpinned 3rd party Action 'actor_trusted_checkout.yml' step $@ uses 'completely/fakeaction' with ref 'v2', not a pinned commit hash | .github/workflows/actor_trusted_checkout.yml:19:7:23:4 | Uses Step | Uses Step | | .github/workflows/actor_trusted_checkout.yml:23:13:23:37 | fakerepo/comment-on-pr@v1 | Unpinned 3rd party Action 'actor_trusted_checkout.yml' step $@ uses 'fakerepo/comment-on-pr' with ref 'v1', not a pinned commit hash | .github/workflows/actor_trusted_checkout.yml:23:7:26:21 | Uses Step | Uses Step | | .github/workflows/artifactpoisoning21.yml:13:15:13:49 | dawidd6/action-download-artifact@v2 | Unpinned 3rd party Action 'Pull Request Open' step $@ uses 'dawidd6/action-download-artifact' with ref 'v2', not a pinned commit hash | .github/workflows/artifactpoisoning21.yml:13:9:18:6 | Uses Step | Uses Step |