diff --git a/codeql-custom-queries-actions/example.ql b/codeql-custom-queries-actions/example.ql new file mode 100644 index 0000000..5406bf9 --- /dev/null +++ b/codeql-custom-queries-actions/example.ql @@ -0,0 +1,61 @@ +// /** +// * @name Empty block +// * @kind problem +// * @problem.severity warning +// * @id go/example/empty-block +// */ + +// import actions + +// select 1 + + +/** + * @name Unpinned tag for a non-immutable Action in workflow + * @description Using a tag for a non-immutable Action that is not pinned to a commit can lead to executing an untrusted Action through a supply chain attack. + * @kind problem + * @security-severity 5.0 + * @problem.severity warning + * @precision medium + * @id actions/unpinned-tag + * @tags security + * actions + * external/cwe/cwe-829 + */ + +import actions +import codeql.actions.security.UseOfUnversionedImmutableAction + +bindingset[version] +private predicate isPinnedCommit(string version) { version.regexpMatch("^[A-Fa-f0-9]{40}$") } + +bindingset[nwo] +private predicate isTrustedOwner(string nwo) { + // Gets the segment before the first '/' in the name with owner(nwo) string + 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 + uses.getEnclosingWorkflow() = workflow and + ( + workflow.getName() = name + or + not exists(workflow.getName()) and workflow.getLocation().getFile().getBaseName() = name + ) and + uses.getVersion() = version and + not isTrustedOwner(nwo) 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 + + "', not a pinned commit hash", uses, uses.toString() diff --git a/codeql-custom-queries-actions/exclusions.yml b/codeql-custom-queries-actions/exclusions.yml new file mode 100644 index 0000000..1c2a15a --- /dev/null +++ b/codeql-custom-queries-actions/exclusions.yml @@ -0,0 +1,9 @@ +extensions: + - addsTo: + pack: codeql/actions-all + extensible: trustedActionsOwnerDataModel + data: + - ["actions"] + - ["github"] + - ["advanced-security"] + - ["company-x"] diff --git a/codeql-custom-queries-actions/qlpack.yml b/codeql-custom-queries-actions/qlpack.yml new file mode 100644 index 0000000..6fd8fac --- /dev/null +++ b/codeql-custom-queries-actions/qlpack.yml @@ -0,0 +1,11 @@ +# Change 'getting-started' to the name of a user or organization that you have write access to. +name: getting-started/codeql-extra-queries-actions +version: 0.0.0 +extractor: actions +dependencies: + # This uses the latest version of the codeql/go-all library. + # You may want to change to a more precise semver string. + codeql/actions-all: "*" + +dataExtensions: + - exclusions.yml \ No newline at end of file diff --git a/codeql-custom-queries-actions/tests/.github/workflows/test1.yml b/codeql-custom-queries-actions/tests/.github/workflows/test1.yml new file mode 100644 index 0000000..9b9417d --- /dev/null +++ b/codeql-custom-queries-actions/tests/.github/workflows/test1.yml @@ -0,0 +1,11 @@ +# tests/tests.testproj/.github/workflows/ci.yml +name: CI + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@latest # Unpinned — should be flagged diff --git a/codeql-custom-queries-actions/tests/UnpinnedActionsTag.expected b/codeql-custom-queries-actions/tests/UnpinnedActionsTag.expected new file mode 100644 index 0000000..621e94f --- /dev/null +++ b/codeql-custom-queries-actions/tests/UnpinnedActionsTag.expected @@ -0,0 +1 @@ +none diff --git a/codeql-custom-queries-actions/tests/UnpinnedActionsTag.qlref b/codeql-custom-queries-actions/tests/UnpinnedActionsTag.qlref new file mode 100644 index 0000000..a711aa7 --- /dev/null +++ b/codeql-custom-queries-actions/tests/UnpinnedActionsTag.qlref @@ -0,0 +1 @@ +UnpinnedActionsTag.ql diff --git a/codeql-custom-queries-actions/tests/test.yml b/codeql-custom-queries-actions/tests/test.yml new file mode 100644 index 0000000..9b9417d --- /dev/null +++ b/codeql-custom-queries-actions/tests/test.yml @@ -0,0 +1,11 @@ +# tests/tests.testproj/.github/workflows/ci.yml +name: CI + +on: [push] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@latest # Unpinned — should be flagged diff --git a/codeql-custom-queries-actions/tests/test2.yml b/codeql-custom-queries-actions/tests/test2.yml new file mode 100644 index 0000000..7b84a93 --- /dev/null +++ b/codeql-custom-queries-actions/tests/test2.yml @@ -0,0 +1,12 @@ +name: Untrusted workflow + +on: push + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Untrusted step + uses: dodgycorp/bad-action@latest # This should trigger the query diff --git a/codeql-custom-queries-actions/tests/test3.yml b/codeql-custom-queries-actions/tests/test3.yml new file mode 100644 index 0000000..343266b --- /dev/null +++ b/codeql-custom-queries-actions/tests/test3.yml @@ -0,0 +1,12 @@ +name: Untrusted workflow + +on: push + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Untrusted step + uses: company-X/bad-action@latest # This should trigger the query diff --git a/vscode-codeql-starter.code-workspace b/vscode-codeql-starter.code-workspace index 3831057..fb3e438 100644 --- a/vscode-codeql-starter.code-workspace +++ b/vscode-codeql-starter.code-workspace @@ -1,30 +1,9 @@ { "folders": [ - { - "path": "codeql-custom-queries-cpp" - }, - { - "path": "codeql-custom-queries-csharp" - }, - { - "path": "codeql-custom-queries-go" - }, - { - "path": "codeql-custom-queries-java" - }, - { - "path": "codeql-custom-queries-javascript" - }, - { - "path": "codeql-custom-queries-python" - }, - { - "path": "codeql-custom-queries-ruby" - }, - { - "path": "ql" - } - ], + { + "path": "." + } + ], "settings": { "omnisharp.autoStart": false }