diff --git a/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql b/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql index 4c4480d8ad19..c8512e5a1c0c 100644 --- a/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql +++ b/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql @@ -23,6 +23,14 @@ private predicate isTrustedOwner(string nwo) { trustedActionsOwnerDataModel(nwo.substring(0, nwo.indexOf("/"))) } +bindingset[version] +private predicate isPinnedContainer(string version) { + version.regexpMatch("^sha256:[A-Fa-f0-9]{64}$") +} + +bindingset[nwo] +private predicate isContainerImage(string nwo) { nwo.regexpMatch("^docker://.+") } + from UsesStep uses, string nwo, string version, Workflow workflow, string name where uses.getCallee() = nwo and @@ -34,7 +42,7 @@ where ) and uses.getVersion() = version and not isTrustedOwner(nwo) and - not isPinnedCommit(version) and + not (if isContainerImage(nwo) then isPinnedContainer(version) else isPinnedCommit(version)) and not isImmutableAction(uses, nwo) select uses.getCalleeNode(), "Unpinned 3rd party Action '" + name + "' step $@ uses '" + nwo + "' with ref '" + version + diff --git a/actions/ql/src/change-notes/2025-02-14-docker-false-positives.md b/actions/ql/src/change-notes/2025-02-14-docker-false-positives.md new file mode 100644 index 000000000000..387472462205 --- /dev/null +++ b/actions/ql/src/change-notes/2025-02-14-docker-false-positives.md @@ -0,0 +1,5 @@ +--- +category: minorAnalysis +--- + +* Fixed false positives in the query `actions/unpinned-tag` (CWE-829), which will no longer flag uses of Docker-based GitHub actions pinned by the container's SHA256 digest. diff --git a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/unpinned_tags.yml b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/unpinned_tags.yml index 992686fb5aa8..f204816eed4e 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/unpinned_tags.yml +++ b/actions/ql/test/query-tests/Security/CWE-829/.github/workflows/unpinned_tags.yml @@ -9,3 +9,5 @@ jobs: - uses: foo/bar - uses: foo/bar@v1 - uses: foo/bar@25b062c917b0c75f8b47d8469aff6c94ffd89abb + - uses: docker://foo/bar@latest + - uses: docker://foo/bar@sha256:887a259a5a534f3c4f36cb02dca341673c6089431057242cdc931e9f133147e9 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 848962e26bd6..ed35f1546171 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected @@ -32,3 +32,4 @@ | .github/workflows/test17.yml:20:21:20:63 | sonarsource/sonarcloud-github-action@master | Unpinned 3rd party Action 'Sonar' step $@ uses 'sonarsource/sonarcloud-github-action' with ref 'master', not a pinned commit hash | .github/workflows/test17.yml:19:15:23:58 | Uses Step | Uses Step | | .github/workflows/test18.yml:37:21:37:63 | sonarsource/sonarcloud-github-action@master | Unpinned 3rd party Action 'Sonar' step $@ uses 'sonarsource/sonarcloud-github-action' with ref 'master', not a pinned commit hash | .github/workflows/test18.yml:36:15:40:58 | Uses Step | Uses Step | | .github/workflows/unpinned_tags.yml:10:13:10:22 | foo/bar@v1 | Unpinned 3rd party Action 'unpinned_tags.yml' step $@ uses 'foo/bar' with ref 'v1', not a pinned commit hash | .github/workflows/unpinned_tags.yml:10:7:11:4 | Uses Step | Uses Step | +| .github/workflows/unpinned_tags.yml:12:13:12:35 | docker://foo/bar@latest | Unpinned 3rd party Action 'unpinned_tags.yml' step $@ uses 'docker://foo/bar' with ref 'latest', not a pinned commit hash | .github/workflows/unpinned_tags.yml:12:7:13:4 | Uses Step | Uses Step | diff --git a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected index 365e9c823fac..5d7a94aead0b 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected @@ -299,7 +299,9 @@ edges | .github/workflows/test.yml:14:9:25:6 | Run Step | .github/workflows/test.yml:25:9:33:6 | Run Step | | .github/workflows/test.yml:25:9:33:6 | Run Step | .github/workflows/test.yml:33:9:37:34 | Run Step | | .github/workflows/unpinned_tags.yml:9:7:10:4 | Uses Step | .github/workflows/unpinned_tags.yml:10:7:11:4 | Uses Step | -| .github/workflows/unpinned_tags.yml:10:7:11:4 | Uses Step | .github/workflows/unpinned_tags.yml:11:7:11:61 | Uses Step | +| .github/workflows/unpinned_tags.yml:10:7:11:4 | Uses Step | .github/workflows/unpinned_tags.yml:11:7:12:4 | Uses Step | +| .github/workflows/unpinned_tags.yml:11:7:12:4 | Uses Step | .github/workflows/unpinned_tags.yml:12:7:13:4 | Uses Step | +| .github/workflows/unpinned_tags.yml:12:7:13:4 | Uses Step | .github/workflows/unpinned_tags.yml:13:7:13:101 | Uses Step | | .github/workflows/untrusted_checkout2.yml:7:9:14:6 | Run Step: pr_number | .github/workflows/untrusted_checkout2.yml:14:9:19:72 | Run Step | | .github/workflows/untrusted_checkout3.yml:11:9:12:6 | Uses Step | .github/workflows/untrusted_checkout3.yml:12:9:13:6 | Uses Step | | .github/workflows/untrusted_checkout3.yml:12:9:13:6 | Uses Step | .github/actions/dangerous-git-checkout/action.yml:6:7:11:4 | Uses Step |