From ef1bde7565565cfa42769a900c681ee42922bafa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 10:17:50 +0000 Subject: [PATCH] Widen pinned SHA regex to support SHA-256 (64-char hex) and add tests --- actions/ql/examples/snippets/uses_pinned_sha.ql | 2 +- actions/ql/lib/codeql/actions/Bash.qll | 2 +- actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql | 4 +++- .../Security/CWE-829/.github/workflows/unpinned_tags.yml | 6 ++++++ .../Security/CWE-829/UnpinnedActionsTag.expected | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/actions/ql/examples/snippets/uses_pinned_sha.ql b/actions/ql/examples/snippets/uses_pinned_sha.ql index 84b2cdae0fd..db055a69fc4 100644 --- a/actions/ql/examples/snippets/uses_pinned_sha.ql +++ b/actions/ql/examples/snippets/uses_pinned_sha.ql @@ -8,5 +8,5 @@ import actions from UsesStep uses -where uses.getVersion().regexpMatch("^[A-Fa-f0-9]{40}$") +where uses.getVersion().regexpMatch("^[A-Fa-f0-9]{40}([A-Fa-f0-9]{24})?$") select uses, "This 'uses' step has a pinned SHA version." diff --git a/actions/ql/lib/codeql/actions/Bash.qll b/actions/ql/lib/codeql/actions/Bash.qll index 4975ce6f4cc..3ba6c705f3e 100644 --- a/actions/ql/lib/codeql/actions/Bash.qll +++ b/actions/ql/lib/codeql/actions/Bash.qll @@ -785,7 +785,7 @@ module Bash { /** * Holds if the given regex is used to match an alphanumeric string - * eg: `^[0-9a-zA-Z]{40}$`, `^[0-9]+$` or `^[a-zA-Z0-9_]+$` + * eg: `^[0-9a-zA-Z]{40}([0-9a-zA-Z]{24})?$`, `^[0-9]+$` or `^[a-zA-Z0-9_]+$` */ string alphaNumericRegex() { result = "^\\^\\[([09azAZ_-]+)\\](\\+|\\{\\d+\\})\\$$" } } diff --git a/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql b/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql index c8512e5a1c0..28368075202 100644 --- a/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql +++ b/actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql @@ -15,7 +15,9 @@ import actions import codeql.actions.security.UseOfUnversionedImmutableAction bindingset[version] -private predicate isPinnedCommit(string version) { version.regexpMatch("^[A-Fa-f0-9]{40}$") } +private predicate isPinnedCommit(string version) { + version.regexpMatch("^[A-Fa-f0-9]{40}([A-Fa-f0-9]{24})?$") +} bindingset[nwo] private predicate isTrustedOwner(string nwo) { 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 f204816eed4..6e7612144bc 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 @@ -11,3 +11,9 @@ jobs: - uses: foo/bar@25b062c917b0c75f8b47d8469aff6c94ffd89abb - uses: docker://foo/bar@latest - uses: docker://foo/bar@sha256:887a259a5a534f3c4f36cb02dca341673c6089431057242cdc931e9f133147e9 + # SHA-256 pinned (64 hex chars) - should NOT be flagged + - uses: foo/bar@25b062c917b0c75f8b47d8469aff6c94ffd89abb25b062c917b0c75f8b47d84d + # SHA-1 pinned (40 hex chars) regression - should NOT be flagged + - uses: foo/bar@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 + # Invalid 50-char hex string - should be flagged + - uses: foo/bar@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2a1b2c3d4e5 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 ed35f154617..a9a1d78de28 100644 --- a/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected +++ b/actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected @@ -33,3 +33,4 @@ | .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 | +| .github/workflows/unpinned_tags.yml:19:13:19:70 | foo/bar@a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2a1b2c3d4e5 | Unpinned 3rd party Action 'unpinned_tags.yml' step $@ uses 'foo/bar' with ref 'a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2a1b2c3d4e5', not a pinned commit hash | .github/workflows/unpinned_tags.yml:19:7:19:70 | Uses Step | Uses Step |